I have an Facebook enabled, iOS 5 app that uses a storyboard and segue based navigation and am confused on how to implement "iOS native deep linking." The example code at Improving App Distribution on iOS just displays a UIAlertView
but I am trying to initiate two consecutive seque operations.
For purposes of this question, I've simplified the application to three view controllers: MYCategoryTableViewController
, MYItemsTableViewController
and MYItemViewController
. In the normal flow, the application opens to MYCategoryTableViewController
, which displays a table of categories. When a category is selected by the user, there is a segue to MYItemsTableViewController
which displays a table of items for that selected category. Lastly, when an item is selected, there is a segue to MYItemViewController
which displays an item detail view.
The prepareForSegue
from MYCategoryTableViewController
sets a property on the destination view controller that represents that category:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:@"ITEMS_SEGUE"]) {
MYItemsTableViewController *vc = [segue destinationViewController];
MYCategory *mycategory = [self.fetchedResultsController objectAtIndexPath:[self.tableView indexPathForSelectedRow]];
vc.mycategory = mycategory;
}
}
The prepareForSegue
from MYItemsTableViewController
sets a property on the destination view controller that represents that category:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:@"ITEM_SEGUE"]) {
MYItemViewController *vc = [segue destinationViewController];
MYItem *myitem = [self.fetchedResultsController objectAtIndexPath:[self.tableView indexPathForSelectedRow]];
vc.myitem = myitem;
}
}
Question: I know that I need to implement something in application:openURL
, but not sure what to do next. Assume the incoming URL gives identifiers to lookup the MYCategory
and MYItem
objects. I found performSegueWithIdentifier
but not sure how that interacts with prepareForSegue
and how I set my model objects on the destination view controllers.
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
// get "target_url" from incoming url
// and parse out MYCategory and MYItem identifiers
// something like this???
[self.window makeKeyAndVisible];
[self.window.rootViewController performSegueWithIdentifier:@"ITEM_SEGUE" sender:self];
return [facebook handleOpenURL:url];
}
Update: Selecting programmatically a cell on a tableview doesn't perform associated segue has given me an idea. Maybe I just save off the url from application:openURL:
and let MYCategoryTableViewController
load naturally. Then during viewWillAppear
, call tableView selectRowAtIndexPath
and then performSegueWithIdentifier
to transition to MYItemsTableViewController
. Repeat the same pattern in MYItemsTableViewController
, but clear out the url before the performSegueWithIdentifier
call.
Here is what I got working. In MYAppDelegate
, I captured a string represented the id of the deep link.
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
NSString *deepLinkId;
// more code that parses url
// only deep link if MYCategoryTableViewController is active controller
UIViewController *rootContoller = self.window.rootViewController;
if ([rootContoller isKindOfClass:[UINavigationController class]]) {
UINavigationController *navController = (UINavigationController *)rootContoller;
if ([navController.topViewController isKindOfClass:[MYCategoryTableViewController class]]) {
self.deepLinkId = deepLinkId;
}
}
}
Then, when MYCategoryTableViewController
loads, call selectRowAtIndexPath
and then performSegueWithIdentifier
.
- (void)processDeepLink {
if (_appDelegate.deepLinkId) {
MYItem *myitem = [MYItem lookupById:_appDelegate.deepLinkId inManagedObjectContext:_appDelegate.dataDocument.managedObjectContext];
if (myitem) {
NSIndexPath *indexPath = [self.fetchedResultsController indexPathForObject:myitem.mycategory];
[self.tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionMiddle];
[self performSegueWithIdentifier:@"ITEMS_SEGUE" sender:self];
}
}
}
And in when MYItemViewController
loads, a similar flow.
if (_appDelegate.deepLinkId) {
MYItem *plate = [MYItem lookupById:_appDelegate.deepLinkId inManagedObjectContext:_appDelegate.dataDocument.managedObjectContext];
NSIndexPath *indexPath = [self.fetchedResultsController indexPathForObject:plate];
[self.tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionMiddle];
_appDelegate.deepLinkId = nil;
[self performSegueWithIdentifier:@"ITEM_SEGUE" sender:self];
}
I also had to observe UIApplicationDidBecomeActiveNotification
for the use case when the application was already open.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(processDeepLink)
name:UIApplicationDidBecomeActiveNotification
object:nil];