xcode iOS 6 - 状态保存和恢复

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12567570/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 01:36:49  来源:igfitidea点击:

iOS 6 - State Preservation and Restoration

iphonexcodecocoa-touchios6uikit-state-preservation

提问by Devfly

I have implemented iOS 6 API for state saving, it works - after I quit the app and launch back in for some milliseconds the restored view controller fly in, but then it's replaced by the main view controller I display at launch.

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

I'm setting every time the app launch the root view of the main window, so this must be the issue.

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

Here is my code:

这是我的代码:

- (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;
        }
    });
}

You can see that in -(void)commonInitializationLaunching:(NSDictionary *)launchOptions I'm setting my window's root view. I don't know what to put in there. Perhaps check if there is saved state and then load this method? But how?

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

Thanks!

谢谢!

Here is what I've tried following Rob's advice:

这是我按照 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;
}

with nothing in willFinishLaunching... I also removed by window code from my commonInitializationLaunchingmethod.

什么都没有willFinishLaunching......我也从我的commonInitializationLaunching方法中删除了窗口代码。

回答by rbrown

Storyboards will do most of the heavy lifting for you, such as restoring the window. Using code, however, will not restore the window. You will need to hold on to your root view controller using the encoder. Your code will look something like this:

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

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;
}

Another gotcha to watch out for is to make sure that your UINavigationControllers and UITabBarControllers have restoration identifiers.

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

回答by Rob Napier

State restoration is generally integrated with storyboards. If you're using a storyboard, you should not be creating your own window, view controllers, etc. You should let the storyboard do this for you. What's happening is that the storyboard is doing all the state restoration, and then you're creating a new window and laying it on top of all that. If that's the case, you're probably creating two copies of your UI on every launch. You're just not noticing it.

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



If you are constructing your entire interface in code (not a recommended approach, but it does work), then you need to determine whether state restoration happened before creating your UI. This is fairly simple:

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

  • In your commonInitializationLaunching:, initialize only non-UI elements (things that wouldn't ever be in state-preservation). This is the place to handle things that the UI elements might rely on during state restoration. You don't have any of these in your current code.

  • In application:didDecodeRestorableState:, set an app delegate ivar to indicate that state was restored.

  • In application:didFinishLaunchingWithOptions:, after running commonInitializationLaunching:, check your ivar. If state wasn't restored, create a UI.

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

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

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

Do remember that the commonInitializationLaunching:pattern only exists for backward compatibility with iOS 5. If you don't need that, then just put non-UI in willFinishand UI in didFinish(if state wasn't restored).

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