Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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,

like image 665
Andrei Erdoss Avatar asked Dec 30 '11 13:12

Andrei Erdoss


3 Answers

After trying many different methods, I was able to solve this problem with this:

-(void)viewWillAppear:(BOOL)animated {

    // Check if user is already logged in
    NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
    if ([[prefs objectForKey:@"log"] intValue] == 1) {
        self.view.hidden = YES;
    }
}

-(void)viewDidAppear:(BOOL)animated{
    [super viewDidAppear:animated];

    // Check if user is already logged in
    NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
    if ([[prefs objectForKey:@"log"] intValue] == 1) {
        [self performSegueWithIdentifier:@"homeSeg3" sender:self];
    }
}

-(void)viewDidUnload {
    self.view.hidden = NO;
}
like image 131
AddisDev Avatar answered Oct 22 '22 00:10

AddisDev


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.

like image 40
codyko Avatar answered Oct 22 '22 00:10

codyko


You can set the rootViewController through the AppDelegate by simply setting up a navigation controller, and when you do the check, set the navigation controllers root view to whichever view you want to be shown at that time. I think something like this should work if you add an if statement for what you want to do:

// Override point for customization after application launch.
    RootViewController *rootController = [[RootViewController alloc] initWithNibName:nil bundle:nil];

    UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:rootController];

    self.window.rootViewController = navigationController;
like image 38
Kinetic Stack Avatar answered Oct 22 '22 01:10

Kinetic Stack