I'm trying to use spotlight results to guide the user to the appropriate section within my app.
Here is my structure, hopefully it does a good job illustrating it.
Navigation Controller
|
|-- Main View
|-- About View
|
|-- SplitView Controller (Presented Modally;StoryboardID: PhoneDirectory)
|-- Master View Controller
|-- Detail View Controller
|--Another View
When a search result brings the user to my app the first time all works well. I am able to present the SplitViewController
and then send the user to the appropriate DetailView
.
However, if the user leaves the app at it's current state and goes back to the search and the taps on another result, the user is taken back to the app with the previous view loaded.
I'm not sure how to go about it at this point.
- Do I
pop
the previous view? If so, how? - Do I reload the data in the detail view? If so, how?
- How can I identify that I'm already presenting a view that I need to present with different data?
With the code below I get the following warning, on the 2nd search result selection:
Warning: Attempt to present <PhoneDirectorySplitViewController: 0x7fdf398ab600> on <UINavigationController: 0x7fdf3c831600> whose view is not in the window hierarchy!
Here's the code I have so far (condensed)
AppDelegate.m
- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray * _Nullable))restorationHandler {
NSString *uid = nil;
if ([[userActivity activityType] isEqualToString:CSSearchableItemActionType] || [[userActivity activityType] isEqualToString:@"com.myapp.activity"]) {
uid = [userActivity userInfo][CSSearchableItemActivityIdentifier];
}
if (uid != nil) {
NSNumberFormatter *f = [[NSNumberFormatter alloc] init];
f.numberStyle = NSNumberFormatterDecimalStyle;
NSNumber *idNum = [f numberFromString:uid];
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
UINavigationController *navController = nil;
navController = [storyboard instantiateViewControllerWithIdentifier:@"PhoneDirectory"];
if (navController != nil) {
[[[self window] rootViewController] presentViewController:navController animated:YES completion:nil];
PhoneDirectoryMasterViewController *master = [[[[navController viewControllers] firstObject] childViewControllers] firstObject];
[master selectRowWithId:idNum];
return YES;
}
}
return NO;
}
MasterView.h
- (void)selectRowWithId:(NSNumber *)uid {
[[self displayedPersons] enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(id == %@)", uid];
NSArray *filteredPersonsArray = [obj filteredArrayUsingPredicate:predicate];
if ([filteredPersonsArray count] > 0) {
NSIndexPath *targetIndexPath = [NSIndexPath indexPathForRow:[[[self displayedPersons] objectForKey:key] indexOfObject:filteredPersonsArray[0]] inSection:[[self personIndexTitles] indexOfObject:key]];
[[self tableView] selectRowAtIndexPath:targetIndexPath animated:NO scrollPosition:UITableViewScrollPositionMiddle];
[self performSegueWithIdentifier:@"showPhoneDirectoryDetail" sender:self];
}
}];
}
If you need more info, just let me know.
So after looking through many SO questions/answers here's what I've come up with. It might not be universally, but it works. If someone can make it universal please feel free to submit a new answer.
AppDelegate.m
You need to do some validations checks at proper places. Add this declaration to your
AppDelegate.m
You might need to keep a reference to the
splitViewController
as you need to access it the second time and you must not create a new controller instance every time you need the same. Currently you are creating a newsplitViewController
instance every time you come back to app from outside.Check #1
Check #2
Check #3 (Inside your MasterViewController.m 'selectRowWithId:')
That'd be all you need. Hope this helps.