11

状態を保存するために 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メソッドからウィンドウコードによっても削除しました。

4

2 に答える 2

24

ストーリーボードは、ウィンドウの復元など、ほとんどの面倒な作業を行います。ただし、コードを使用してもウィンドウは復元されません。エンコーダーを使用してルート ビュー コントローラーを保持する必要があります。コードは次のようになります。

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

注意すべきもう 1 つの落とし穴は、 とUINavigationControllerUITabBarController復元識別子があることを確認することです。

于 2012-10-09T21:20:49.007 に答える
6

状態の復元は、通常、ストーリーボードと統合されています。ストーリーボードを使用している場合、独自のウィンドウやビュー コントローラーなどを作成するべきではありません。ストーリーボードにこれを行わせる必要があります。何が起こっているかというと、ストーリーボードがすべての状態の復元を行っているということです。次に、新しいウィンドウを作成して、その上にそれを配置しています。その場合は、起動のたびに UI のコピーを 2 つ作成している可能性があります。あなたはそれに気づいていないだけです。


インターフェイス全体をコードで構築している場合 (推奨される方法ではありませんが、機能します)、UI を作成する前に状態の復元が行われたかどうかを判断する必要があります。これはかなり単純です。

  • では、commonInitializationLaunching:非 UI 要素 (状態が保持されないもの) のみを初期化します。これは、状態の復元中に UI 要素が依存する可能性のあるものを処理する場所です。現在のコードにはこれらのいずれもありません。

  • application:didDecodeRestorableState:、アプリ デリゲート ivar を設定して、状態が復元されたことを示します。

  • application:didFinishLaunchingWithOptions:を実行した後commonInitializationLaunching:、ivar を確認します。状態が復元されなかった場合は、UI を作成します。

パターンは iOS 5 との下位互換性のためにのみ存在することを覚えておいてくださいcommonInitializationLaunching:。それが必要ない場合は、非 UI を入れて UI を入れるだけですwillFinish(didFinish状態が復元されていない場合)。

于 2012-10-01T13:32:48.010 に答える