iOS 6 - сохранение и восстановление состояния

Я реализовал 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 Я устанавливаю корневое представление моего окна. Я не знаю, что туда положить. Может быть, проверить, есть ли сохраненное состояние, а затем загрузить этот метод? Но как?

Спасибо!

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

- (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 метод.

2 ответа

Решение

Раскадровки сделают большую часть тяжелой работы за вас, например, восстановив окно. Использование кода, однако, не восстановит окно. Вы должны будете держаться за свой корневой контроллер представления, используя кодировщик. Ваш код будет выглядеть примерно так:

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с и UITabBarControllers имеют идентификаторы восстановления.

Состояние восстановления обычно интегрируется с раскадровками. Если вы используете раскадровку, вы не должны создавать свое собственное окно, просматривать контроллеры и т. Д. Вы должны позволить раскадровке сделать это за вас. Происходит то, что раскадровка выполняет восстановление состояния, а затем вы создаете новое окно и кладете его поверх всего этого. Если это так, вы, вероятно, создаете две копии своего пользовательского интерфейса при каждом запуске. Вы просто не замечаете этого.


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

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

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

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

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

Другие вопросы по тегам