9

ストーリー ボードを使用しないアプリで状態の復元を行いたいです。状態の復元中にプライマリ アプリの ViewController が 2 回インスタンス化されています。

application:willFinishLaunchingWithOptions私がフローを理解する方法は、アプリケーションの UIWindow とその rootViewController をセットアップするメソッドをpplication:didFinishLaunchingWithOptions使用することです。commonInit私の場合、rootViewController は、UINavigation の rootViewController として機能する「MyMainViewController」という名前のクラスを持つ UINavigationController です。

willEncodeRestorableStateWithCoderこれに加えて、ともそれぞれ扱ってdidDecodeRestorableStateWithCoderいます。しかし、myMainViewController に到達するまでにdidDecodeRestorableStateWithCoder、MyMainViewController の 2 つの別個のインスタンスが作成されていることがわかります。

復元中にUIViewControllerが1つだけ作成されるようにする方法は何ですか?

復元中の呼び出しの順序:

  • application:willFinishLaunchingWithOptions を介して新しいインスタンス MyMainViewController (#1) を作成します。
  • MyMainViewController の viewControllerWithRestorationIdentifierPath:coder が呼び出され、MainViewController が復元されます (#2)
  • application:didDecodeRestorableStateWithCoder: が呼び出され、 UINavigationController がデコードされて self.window に割り当てられます

AppDelegate で行っていることは次のとおりです。

NSString * const kRootViewControllerKey = @"RootViewControllerKey";

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

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

- (void)commonInitWithOptions:(NSDictionary *)launchOptions {

    static dispatch_once_t predicate;
    dispatch_once(&predicate, ^ {

        // While this will be called only once during the lifetype of the app, when the process is killed 
        // and restarted, I wind up with an instance of MyMainViewController created first from here
        // and then once again, during MyMainViewController's viewControllerWithRestorationIdentifierPath:coder 
        // that's invoked later on. 

        UIViewController *rootViewController = [MyMainViewController alloc] init];
        UINavigationController *aNavController = [[UINavigationController alloc] initWithRootViewController:rootViewController];

        aNavController.navigationBarHidden = YES;
        aNavController.restorationIdentifier = NSStringFromClass([aNavController class]);

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

        self.window = aWindow;
    });
}

// Encode app delegate level state restoration data
- (void)application:(UIApplication *)application willEncodeRestorableStateWithCoder:(NSCoder *)coder {
    [coder encodeObject:self.window.rootViewController forKey:kRootViewControllerKey];
}

// Decode app delegate level state restoration data
- (void)application:(UIApplication *)application didDecodeRestorableStateWithCoder:(NSCoder *)coder {

    // Find the preserved root view controller and restore with it
    UINavigationController *navControlller = [coder decodeObjectForKey:kRootViewControllerKey];

    if (navControlller) {
        self.window.rootViewController = navControlller;
    }

}
4

1 に答える 1

0

ルート ビュー クラスのインスタンスは 1 つしかないはずなので、クラス メソッドを追加してクラスを割り当てて初期化し、それ以外の場合は値を返すことで解決しました。

+ (id) initOnce {
    static id view_ref;

    if(!view_ref)
        view_ref = [[UIViewController alloc] init];

    return view_ref;
}

[UIViewController initOnce] を介してクラスが初期化されると、willFinishLaunchingWithOptions または viewControllerWithRestorationIdentifierPath のいずれの場合でも、常に同じビュー参照が返されます。

于 2014-02-18T19:33:00.617 に答える