9

I'd like to do state restoration in my app that doesn't use story boards. I'm seeing my primary app ViewController instantiated twice during state restoration - how do you ensure that it's only created once?

The way I understand the flow, application:willFinishLaunchingWithOptions and application:didFinishLaunchingWithOptions would use a commonInit method which would setup the applications UIWindow and its rootViewController. In my case, the rootViewController is a UINavigationController with a class named 'MyMainViewController' serving as UINavigation's rootViewController.

Along side this I'm also handling willEncodeRestorableStateWithCoder and didDecodeRestorableStateWithCoder, respectively. But it seems that by the time I get to my didDecodeRestorableStateWithCoder, I see two separate instances of MyMainViewController created.

What's the way to ensure that only one UIViewController is created during restoration?

Order of calls during restoration:

  • Create new instance MyMainViewController (#1) via application:willFinishLaunchingWithOptions:
  • MyMainViewController's viewControllerWithRestorationIdentifierPath:coder invoked and MainViewController is restored (#2)
  • application:didDecodeRestorableStateWithCoder: is called and UINavigationController is decoded and assigned to self.window

Here's what I'm doing in my AppDelegate:

NSString * const kRootViewControllerKey = @"RootViewControllerKey";

- (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    [self commonInitWithOptions:launchOptions];
    return YES;
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    [self commonInitWithOptions:launchOptions];
    return YES;
}

- (void)commonInitWithOptions:(NSDictionary *)launchOptions {

    static dispatch_once_t predicate;
    dispatch_once(&predicate, ^ {

        // While this will be called only once during the lifetype of the app, when the process is killed 
        // and restarted, I wind up with an instance of MyMainViewController created first from here
        // and then once again, during MyMainViewController's viewControllerWithRestorationIdentifierPath:coder 
        // that's invoked later on. 

        UIViewController *rootViewController = [MyMainViewController alloc] init];
        UINavigationController *aNavController = [[UINavigationController alloc] initWithRootViewController:rootViewController];

        aNavController.navigationBarHidden = YES;
        aNavController.restorationIdentifier = NSStringFromClass([aNavController class]);

        UIWindow *aWindow = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
        aWindow.rootViewController = aNavController;
        aWindow.restorationIdentifier = NSStringFromClass([window class]);

        self.window = aWindow;
    });
}

// Encode app delegate level state restoration data
- (void)application:(UIApplication *)application willEncodeRestorableStateWithCoder:(NSCoder *)coder {
    [coder encodeObject:self.window.rootViewController forKey:kRootViewControllerKey];
}

// Decode app delegate level state restoration data
- (void)application:(UIApplication *)application didDecodeRestorableStateWithCoder:(NSCoder *)coder {

    // Find the preserved root view controller and restore with it
    UINavigationController *navControlller = [coder decodeObjectForKey:kRootViewControllerKey];

    if (navControlller) {
        self.window.rootViewController = navControlller;
    }

}
Willam Hill
  • 1,532
  • 1
  • 16
  • 27

1 Answers1

0

There's only ever supposed to be one instance of my root view class, so I solved it by adding a class method to alloc and init the class only once and return the value otherwise:

+ (id) initOnce {
    static id view_ref;

    if(!view_ref)
        view_ref = [[UIViewController alloc] init];

    return view_ref;
}

Now when the class is initialized via [UIViewController initOnce], the same view reference always gets returned, whether during willFinishLaunchingWithOptions or viewControllerWithRestorationIdentifierPath.

jasonjwwilliams
  • 2,512
  • 3
  • 19
  • 14