【问题标题】:iOS 6 - State Preservation and RestorationiOS 6 - 状态保存和恢复
【发布时间】:2012-09-16 01:30:15
【问题描述】:

我已经实现了用于状态保存的 iOS 6 API,它可以工作 - 在我退出应用程序并重新启动几毫秒后,恢复的视图控制器飞入,但随后它被我在启动时显示的主视图控制器取代。

我在每次应用启动主窗口的根视图时进行设置,所以这一定是问题所在。

这是我的代码:

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

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

- (void)commonInitializationLaunching:(NSDictionary *)launchOptions
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{

        self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
        // Override point for customization after application launch.
        static NSString *const kKeychainItemName = @"OAuthGoogleReader";
        self.viewController = [[ViewController alloc] initWithNibName:@"ViewController" bundle:nil];
        self.navController = [[UINavigationController alloc] initWithRootViewController:self.viewController];

        GTMOAuth2Authentication *auth;
        auth = [GTMOAuth2ViewControllerTouch authForGoogleFromKeychainForName:kKeychainItemName
                                                                     clientID:kClientID
                                                                 clientSecret:kClientSecret];

        self.window.rootViewController = self.navController;

        [self.window makeKeyAndVisible];

        BOOL isSignedIn = [auth canAuthorize];
        if (isSignedIn) {
            NSLog(@"Signed");
        }else{
            NSString *scope = @"https://www.google.com/reader/api/";

            GTMOAuth2ViewControllerTouch *viewController;
            viewController = [[GTMOAuth2ViewControllerTouch alloc] initWithScope:scope
                                                                        clientID:kClientID
                                                                    clientSecret:kClientSecret
                                                                keychainItemName:kKeychainItemName
                                                                        delegate:self
                                                                finishedSelector:@selector(viewController:finishedWithAuth:error:)];
            [self.navController pushViewController:viewController animated:YES];
            //        self.window.rootViewController = viewController;
        }
    });
}

你可以在 -(void)commonInitializationLaunching:(NSDictionary *)launchOptions 中看到 我正在设置我的窗口的根视图。我不知道在里面放什么。也许检查是否有保存状态然后加载此方法?但是怎么做呢?

谢谢!

这是我按照 Rob 的建议尝试过的:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    if (!self.isRestored) {
        self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    }
    [self commonInitializationLaunching:launchOptions];
    [self.window makeKeyAndVisible];
    return YES;
}

willFinishLaunching 中没有任何内容... 我还通过窗口代码从我的commonInitializationLaunching 方法中删除了。

【问题讨论】:

  • 我的回答有帮助吗?一些反馈会很棒。

标签: iphone xcode cocoa-touch ios6 uikit-state-preservation


【解决方案1】:

故事板将为您完成大部分繁重的工作,例如修复窗户。但是,使用代码不会恢复窗口。您将需要使用编码器保留您的根视图控制器。您的代码将如下所示:

NSString * const AppDelegateRootVCKey = @"AppDelegateRootVCKey";

- (void)application:(UIApplication *)application willEncodeRestorableStateWithCoder:(NSCoder *)coder {
    [coder encodeObject:self.window.rootViewController forKey:AppDelegateRootVCKey];
}

- (void)application:(UIApplication *)application didDecodeRestorableStateWithCoder:(NSCoder *)coder {

    // Grabs the preserved root view controller.
    UIViewController * vc = [coder decodeObjectForKey:AppDelegateRootVCKey];

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

        // The green color is just to make it obvious if our view didn't load properly.
        // It can be removed when you are finished debugging.
        window.backgroundColor = [UIColor greenColor];

        self.window = window;
    }
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    if (!self.window) {

        UIWindow *window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];

        // The blue color is just to make it obvious if our view didn't load properly.
        // It can be removed when you are finished debugging.
        window.backgroundColor = [UIColor blueColor];

        UIViewController *root = // However you create your root.

        window.rootViewController = root;
        window.restorationIdentifier = NSStringFromClass([window class]);

        self.window = window;
    }

    [self commonInitializationLaunching:launchOptions];
    [self.window makeKeyAndVisible];

    return YES;
}

另一个需要注意的问题是确保您的UINavigationControllers 和UITabBarControllers 具有恢复标识符。

【讨论】:

  • 您的回答似乎很合乎逻辑,尽管我无法在我的测试程序中实现它,并且将它留了一段时间。感谢您的精彩回答!
【解决方案2】:

状态恢复通常与故事板集成在一起。如果您使用故事板,则不应创建自己的窗口、视图控制器等。您应该让故事板为您完成这些工作。正在发生的事情是情节提要正在执行所有状态恢复,然后您正在创建一个新窗口并将其放置在所有这些之上。如果是这种情况,您可能会在每次启动时创建两个 UI 副本。你只是没有注意到它。


如果您是在代码中构建整个界面(不是推荐的方法,但它确实有效),那么您需要在创建 UI 之前确定状态恢复是否发生。这很简单:

  • 在您的 commonInitializationLaunching: 中,仅初始化非 UI 元素(永远不会处于状态保留状态的元素)。这是处理状态恢复期间 UI 元素可能依赖的事物的地方。您当前的代码中没有这些。

  • application:didDecodeRestorableState: 中,设置应用委托 ivar 以指示状态已恢复。

  • application:didFinishLaunchingWithOptions: 中,运行commonInitializationLaunching: 后,检查您的ivar。如果状态未恢复,请创建 UI。

请记住,commonInitializationLaunching: 模式的存在只是为了向后兼容 iOS 5。如果您不需要它,那么只需将非 UI 放入 willFinish 并将 UI 放入 didFinish(如果状态不是已恢复)。

【讨论】:

  • 非常好的方法,但我现在得到的只是黑屏 - 当我将 [self.windows makeKeyAndVisible] 移动到依赖 iVar isRestored 时,我什至尝试使用带有 Storyboard 的简单 Master-Detail 应用程序,并且没用..有什么我遗漏的吗?
  • 在所有情况下都需要调用 -makeKeyAndVisible。在不恢复时,您应该只创建一个 UIWindow。
  • 还是不行——黑屏。检查我的问题的编辑
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-12
  • 2014-05-14
相关资源
最近更新 更多