在状态恢复期间创建和恢复UIViewControllers的正确方法?

时间:2013-07-18 22:30:02

标签: ios state-restoration

我想在不使用故事板的应用程序中进行状态恢复。我看到我的主应用程序ViewController在状态恢复期间实例化了两次 - 你如何确保它只创建一次?

我理解流程的方式application:willFinishLaunchingWithOptionspplication:didFinishLaunchingWithOptions将使用commonInit方法设置应用程序UIWindow及其rootViewController。在我的例子中,rootViewController是一个UINavigationController,它有一个名为'MyMainViewController'的类,作为UINavigation的rootViewController。

除此之外,我还分别处理willEncodeRestorableStateWithCoderdidDecodeRestorableStateWithCoder。但似乎当我到达didDecodeRestorableStateWithCoder时,我看到MyMainViewController创建了两个独立的实例。

确保在恢复期间只创建一个UIViewController的方法是什么?

恢复期间的通话顺序:

  • 通过应用程序创建新实例MyMainViewController(#1):willFinishLaunchingWithOptions:
  • MyMainViewController的viewControllerWithRestorationIdentifierPath:调用编码器并且 MainViewController已恢复(#2)
  • application:didDecodeRestorableStateWithCoder:被调用并且UINavigationController被解码并分配给self.window

以下是我在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;
    }

}

1 个答案:

答案 0 :(得分:0)

我只应该是我的根视图类的一个实例,所以我通过添加一个类方法来解决它,只启动一次类,然后返回该值:

+ (id) initOnce {
    static id view_ref;

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

    return view_ref;
}

现在,当通过[UIViewController initOnce]初始化类时,无论是在willFinishLaunchingWithOptions还是viewControllerWithRestorationIdentifierPath期间,都会返回相同的视图引用。