iOS 6 - Государственное сохранение и восстановление

Я реализовал API iOS 6 для экономии состояния, он работает - после того, как я покинул приложение и запустил его за несколько миллисекунд, обновленный контроллер просмотра влетает, но затем он заменяется основным контроллером представления, отображаемым при запуске.

Я устанавливаю каждый раз, когда приложение запускает корневой вид главного окна, поэтому это должно быть проблемой.

Вот мой код:

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

Вы можете видеть, что in - (void) commonInitializationLaunching: (NSDictionary *) launchOptions Я устанавливаю свой вид корневого окна. Я не знаю, что там положить. Возможно, проверьте, сохранено ли состояние, а затем загрузите этот метод? Но как?

Благодарю!

Вот что я пробовал после Роба:

- (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.

Ответ 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;
}

Еще одна причина, по которой нужно следить, - убедиться, что ваш UINavigationController и UITabBarController имеют идентификаторы восстановления.

Ответ 2

Государственная реставрация, как правило, интегрирована с раскадровки. Если вы используете раскадровку, вам не следует создавать собственное окно, просматривать контроллеры и т.д. Вы должны позволить раскадровке сделать это за вас. Что происходит, так это то, что раскадровка выполняет все государственное восстановление, а затем вы создаете новое окно и кладете его поверх всего этого. В этом случае вы, вероятно, создаете две копии вашего пользовательского интерфейса при каждом запуске. Ты просто не замечаешь этого.


Если вы создаете весь свой код в коде (не рекомендуется, но он работает), вам необходимо определить, произошло ли восстановление состояния перед созданием вашего пользовательского интерфейса. Это довольно просто:

  • В вашем commonInitializationLaunching: инициализируйте только элементы, отличные от UI (вещи, которые никогда не были бы в сохранении состояния). Это место для обработки вещей, на которые могут опираться элементы пользовательского интерфейса во время восстановления состояния. У вас нет ни одного из них в вашем текущем коде.

  • В application:didDecodeRestorableState: установите делегат приложения ivar, чтобы указать, что состояние было восстановлено.

  • В application:didFinishLaunchingWithOptions: после запуска commonInitializationLaunching: проверьте свой ivar. Если состояние не было восстановлено, создайте пользовательский интерфейс.

Помните, что commonInitializationLaunching: существует только для обратной совместимости с iOS 5. Если вам это не нужно, то просто поместите не-интерфейс в willFinish и UI в didFinish (если состояние не было восстановлено).