State restoration for modal view controllers
In my first post about state restoration on iOS 6 (or newer), I explained how you should use restorationIdentifier
for the view controllers that are part of the on-load UI (and thus created in AppDelegate) and restorationClass
to create and return controllers which are deeper in navigation stack.
If you do that, UIKit will take care of restoring the UITabBarController
and UINavigationController
and you just deal with view controllers beyond the topViewController
inside the navigation controller hierarchy.
That’s still a good general guideline. However, as is usually the case, there are exceptions.
Restoring modal navigation controllers
One typical case is this: you tap a button which modally presents UIViewController embedded in UINavigationController. I have two instances of this in my currency converter iPhone app, Banca:
This is typical code that opens the modal NC:
RTAboutViewController *vc = [[RTAboutViewController alloc] init];
UINavigationController *nc = [[UINavigationController alloc] initWithRootViewController:vc];
nc.restorationIdentifier = @"AboutNC";
[self presentViewController:nc animated:YES completion:nil];
RTAboutViewController
has its own restorationClass
to take care of its restoration, but what/how restores its parent UINavigationController
? At first I thought I need to subclass UINC and add restorationClass but quickly realized that’s stupid; no way Apple devs would leave that as only solution.
Of course they didn’t.
It’s the AppDelegate that does it.
- (UIViewController *)application:(UIApplication *)application
viewControllerWithRestorationIdentifierPath:(NSArray *)identifierComponents
coder:(NSCoder *)coder {
// return various navigation controllers here.
// actual view controlers will each be returned in their own classes
NSString *lastIdentifier = [identifierComponents lastObject];
if ([lastIdentifier isEqualToString:@"MainNC"]) {
return self.window.rootViewController;
} else if ([lastIdentifier isEqualToString:@"AboutNC"]) {
UINavigationController *nc = [[UINavigationController alloc] init];
nc.restorationIdentifier = @"AboutNC";
return nc;
} else if ([lastIdentifier isEqualToString:@"CurrenciesNC"]) {
UINavigationController *nc = [[UINavigationController alloc] init];
nc.restorationIdentifier = @"CurrenciesNC";
return nc;
}
return nil;
}
Easy and works exactly as you expect it to.