Search code examples
iphoneiosauthenticationios5storyboard

Best practice on showing a one time login screen w/ storyboards


I've seen similar questions here, but not with a clear answer. So I have one modal login view with the classic username/password form, a Facebook login button and a Sign Up button which I would like to show when the user starts the app for the very first time. From what I found there are two ways to implement this, with shortcumings.

  1. in AppDelegate's didFinishLaunchingWithOptions a conditional is set to check if the user is logged in. If not the rootViewController is set to the loginViewController. After a succesful login a segue takes place to the main view of the app. My problem with this aproach is that I am not sure how to reset the rootViewController to the main view. Is that possible and how?

Are there any other ways to show the login modal without setting the rootViewController? Meaning I would keep ther rVC to the main view.

  1. in the main view controller in the viewDidAppear a conditional checks if the user is logged in. If not a segue to the loginVC is performed. When the user succesfully logs in he is returned to the main view which dismissed the modal login view. The problem with this aproach is that the main view is briefly shown, which I would prefer not to do.

  2. Any other ideas? Please let me know what is the best practice when it comes to this scenario. Thank you in advance,


Solution

  • In my opinion the best strategy for something like this is a login screen that's already presented over the main view controller when the app launches, and is dismissed nicely and deallocated after the user signs in. I've found that most of the previously suggested solutions (as well as the suggestions here: Best practices for Storyboard login screen, handling clearing of data upon logout) do not accomplish this elegantly.

    After some experimenting yesterday, I think the best way of doing this is by using child view controllers:

    1. Choose your Main Interface storyboard in Xcode just as you normally would (there is no need to add anything to your appDelegate

    main interface

    2. Add the following to your main view controller in viewDidLoad:

    // If user is not logged in, show login view controller
    if (!isLoggedIn) {
        // Instantiate Login View Controller from storyboard
        UIStoryboard *mainSB = [UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]];
        UIViewController *loginVC = [mainSB instantiateViewControllerWithIdentifier:@"Login"];
    
        // Set the Login View Controller's frame
        loginVC.view.frame = self.view.bounds;
    
        // Add login screen as a subview and as a child view controller
        [self.view addSubview:loginVC.view];
        [self addChildViewController:loginVC];
        [loginVC didMoveToParentViewController:self];
    
        // Maintain a reference to the Login screen so we can dismiss it later
        _loginVC = loginVC;
    }
    

    3. After the user has logged in, inform your main view controller by either using notifications or a delegate. Then you can animate the login screen away in any way you wish. Here I'm using a dissolve animation:

    // Animate out the category chooser
    [UIView animateWithDuration:0.2 animations:^{
        // Dissolve the login screen away
        [_loginVC.view setAlpha:0];
    } completion:^(BOOL finished) {
        // Remove login screen as a child view controller
        [_loginVC willMoveToParentViewController:nil];
        [_loginVC.view removeFromSuperview];
        [_loginVC removeFromParentViewController];
    
        // nil out property
        _loginVC = nil;
    }];
    

    And that's it! This way, the main view controller is always your window's root view controller, the login screen gets deallocated after the user logs in, and there is no flicker when first presenting the login screen.