web-dev-qa-db-ja.com

iOSアプリのロード後にルートビューコントローラーを変更する。

ユーザーがログインした後ではなく、アプリの読み込み時にログイン画面を表示するために、ユーザーが正常にログインしたときにNSUserDefaultsに認証オブジェクトを追加することにしました。アプリが起動すると、そのauthパラメーターがチェックされ、それに応じてView Controllerが設定されます(ユーザーがauthの場合はフィードが表示され、そうでない場合はログイン画面が表示されます)後者の場合、アプリがありますユーザーがログインした後、デリゲートはルートビューコントローラーをフィードにリセットします。これは悪い習慣ですか、それともこれを行うためのより良い方法がありますか?

アプリデリゲート

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary     *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    IIViewDeckController* deckController = [self generateControllerStack];
    self.rightController = deckController.rightController;
    self.centerController = deckController.centerController;

    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];

    if([[defaults objectForKey:@"auth"] isEqualToNumber:[NSNumber numberWithInt:1]]){
        self.window.rootViewController = deckController;
    }else{
        UIStoryboard *sb = [UIStoryboard storyboardWithName:@"MainStoryboard"
                                                 bundle:nil];
        UIViewController* vc = [sb instantiateViewControllerWithIdentifier:@"loginViewController"];
        self.window.rootViewController = vc;
    }
    [self.window makeKeyAndVisible];
    [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleBlackOpaque animated:NO];
    return YES;
}

- (void) setRoots
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    IIViewDeckController* deckController = [self generateControllerStack];
    self.rightController = deckController.rightController;
    self.centerController = deckController.centerController;
    self.window.rootViewController = deckController;
    [self.window makeKeyAndVisible];
}

ログインビューコントローラ

- (IBAction)loginClick:(id)sender {
    if([_emailField.text length]>0&&[_passField.text length]>0){
        NSString *user = _emailField.text;
        NSString *pass = _passField.text;
        [[API sharedInstance] login:user andPass:pass onCompletion:^(NSDictionary *json){
            NSLog(@"%@", json);
            if(![json objectForKey:@"error"]){
                [API sharedInstance].authorized = 1;
                NSNumber *auth = [NSNumber numberWithInt:1];
                NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
                [defaults setObject:auth forKey:@"auth"];
                [defaults synchronize];

                captureYouAppDelegate *app = [[UIApplication sharedApplication] delegate];
                [app setRoots]; 
            }else{
                [API sharedInstance].authorized = 0;
            }
        }];
    }else{
        if([_emailField.text length]<1){
            [_emailField becomeFirstResponder];
        }else{
            [_passField becomeFirstResponder];
        }
    }
}

それよりも良い方法や簡単な方法があるのだろうかと思います。ありがとうございました!

11
Misbah Khan

明確にするために。以前は問題なくUIWindowのrootViewControllerをリセットしていましたが、デバイスの回転を許可しているときにリセットしようとすると、いくつかの問題が発生しました—回転が機能しなくなっただけです。

デバッグしようとしたときに、Appleのドキュメントから直接次のことがわかりました。以下のリンクには、UIWindowの操作に関するいくつかのガイドラインがあります。これらはすべてデバイスの回転に関連していますが、それでも知っておくとよいでしょう。

簡単に言うと、ルートコントローラーを使用して、子ビューコントローラーを追加します。その後、問題なく子VCを交換できます。

•ビューコントローラのUIViewプロパティをサブビューとしてUIWindowに追加しました。

開発者は、ビューコントローラのviewプロパティをUIWindowのサブビューとして追加することをお勧めしません。アプリケーションのルートビューコントローラーは、Interface Builderで、または実行時にapplication:didFinishLaunchingWithOptions:から戻る前に、アプリウィンドウのrootViewControllerプロパティに割り当てる必要があります。複数のViewControllerからのコンテンツを同時に表示する必要がある場合は、独自のコンテナView Controllerを定義し、それをルートViewControllerとして使用する必要があります。カスタムコンテナビューコントローラの作成を参照してください。

詳細については、 この技術的なQ&A を確認してください。

6
WCByrne

window.rootViewControllerをリセットすることは悪い習慣ではないと思います。ただし、ウィンドウを再作成する必要はありません。
以前のViewControllerを使用したくない場合は、ウィンドウのrootViewControllerを新しいViewControllerに置き換えるだけです。以前のViewControllerに戻したい場合は、-presentViewController: animated: completion:を使用してViewControllerを提示することをお勧めします。

4
liuyaodong

ウィンドウを再度割り当てる必要はありません。これを直接設定できます。

window.rootViewController = yourVC;
0
Divyam shukla

ステップバイステップ私はUINavigationControllerの助けを借りてrootviewcontrollerを使用するためのグッドプラクティスを示しています

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {  
    // Override point for customization after application launch.

    self.splash = [[SplashViewController alloc] initWithNibName: @"SplashViewController" bundle: nil];  
    self.window.rootViewController = self.splash;  
    [self.window makeKeyAndVisible];  
    DLog(@"finished initializing .....");  
    [self setRootViewController];  

    return YES;  
}



- (void) setRootViewController  
{  
    DLog(@"setRootViewController");  
    if (self.sessionManager.isLoggedIn)  
    {  
            [self navigateToHomeController];  

    } else {  
            [self navigateToLoginController];  
      }  
}


- (void) navigateToHomeController  
{  
    UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"kStoryBoard" bundle: nil];  
    UINavigationController* homeNavigationController =  [storyboard instantiateViewControllerWithIdentifier:@"kHomeNavController"];  
    NSArray* controllers = [homeNavigationController viewControllers];  
    if([controllers lastObject])  
    {  
        if ([[controllers objectAtIndex:0] isKindOfClass:[HomeViewController class]]) {  
            HomeViewController* homeController = (HomeViewController*) [controllers objectAtIndex:0];  
            self.window.rootViewController = [[OLNavigationViewController alloc] initWithRootViewController: homeController]; 
        }  
    }  
}



- (void) navigateToLoginController  
{  
    UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"kStoryBoard" bundle: nil];  
    UINavigationController* loginNavigationController = [storyboard instantiateViewControllerWithIdentifier:@"kLoginNavController"];  
    if ([loginNavigationController isKindOfClass:[OLLoginViewController class]]) {  
        OLLoginViewController* loginController = (OLLoginViewController*) loginNavigationController;  
        loginController.shouldHideToolBar = YES;  
        self.window.rootViewController = [[UINavigationController alloc] initWithRootViewController: loginController];  
    }
}
0
TheCodeTalker