State Restoration Debugging

I’m curious if anyone has some helpful hints when state restoration doesn’t work. I have the following situation:


UIWindow subclass

-UITabViewController subclass


Each tab has:

—UISplitViewController subclass

—UINavigationController subclass

-UIVC Master subclass

-UIVC Detail subclass


Its all in code - no storyboard. I’m creating the window, tab, split, in the willFinishLaunching so that its all ready for state restoration. I have the restoration identifiers setup. I have the detail view controller conforming to UIViewControllerRestoration and viewControllerWithRestorationIdentifierPath does get called. I’m creating the detail VC, and I’m seeing it all get decoded properly.


I’ve read every article I can find on state restoration, the docs, etc… and I just can’t find anything that provides common reasons for it not working. Here is what’s driving me crazy: I got it all working once. Then I went to apply it to another tab and its View controllers, and I’ve never gotten it to work again.


I’ve always hated working with state restoration, and I’m about to go old-school.

Replies

I see this is a pretty old question.

I have an app that has to implement pretty complicated logic on app launch to determine what UI to show to the user, but also supports state restoration. So without going into all the things my app has to do, I'll just explain what I discovered.

What I noticed is, when I create my UIWindow programmatically in my AppDelgate, the state restoration system creates the view controllers to restore from the last launch (-application:didDecodeRestorableStateWithCoder: is called) but then all the view controllers *immediately dealloc*. The system doesn't install the view controller's on the app delegate's window if it is created programmatically. The state restoration code isn't robust enough to handle this. If the window is created automatically by using a "Main Interface" (storyboard file) the state restoration view controllers do get added the AppDelegate's window automatically, but only if UIKit makes the window.

My AppDelegate instantiates the window the first time the getter is called:

Code Block
-(UIWindow*)window
{
    if (_window == nil)
    {
        CGRect bounds = [UIScreen mainScreen].bounds;
        _window = [[UIWindow alloc]initWithFrame:bounds];
    }
    return _window;
}


Anyway, the the state restoration system doesn't call the window getter on my app delegate, and it just makes view controllers that aren't retained by anything and throws them away.

Only solution I was able to come with is to manually restore the root view controller in the app delegate via -application:viewControllerWithRestorationIdentifierPath:coder:

Code Block
-(UIViewController*)application:(UIApplication*)application
viewControllerWithRestorationIdentifierPath:(NSArray<NSString*>*)identifierComponents
                                   coder:(NSCoder*)coder
{
    if ([identifierComponents.lastObject isEqualToString:@"RootVCIDHere"])
    {
        UIStoryboard *storyboard = [coder decodeObjectForKey:UIStateRestorationViewControllerStoryboardKey];
UIViewController *rootRestoredVC = [storyboard instantiateInitialViewController];
self.window.rootViewController = rootRestoredVC; // <-- ADD it to the window manually so the view controllers don't just dealloc right after being created!
return rootRestoredVC;
    }
return nil;
}