All,
I've been researching the best way to display a UINavigationController with a Login/Signup View prior to the UITabBarController displaying when a user initially opens the app. I've read Best practices for Storyboard login screen, handling clearing of data upon logout and Best practice on showing a one time login screen w/ storyboards but neither provide an entire solution. The first involves using the AppDelegate and changing the RootViewController. While this is good for an initial login screen, it makes the view somewhat non-reusable as it will always replace the RootViewController which isn't necessarily a good choice if you allow the app to be used without a logged in user or allow anonymous user login and then have the app pull a large amount of web data. If I set the RootViewController it will require me to pull all that data down again should I allow a user to later in the app experience login or signup.
I've instead opted to use two storyboards. One for the main flow of the app and one for the login controller. The "Main" storyboard has the Initial View Controller as a subclassed UITabBarController called "MainTBC". I wanted the LoginSignupVC to be placed inside of a UINavigationController and to always appear before the first tab of the app. As a result I've got the following code largely inspired by codyko on this post:
- (void) viewDidLoad {
[super viewDidLoad];
if (![PFUser currentUser]) {
// user is not logged in
// grab a reference to the LoginSignupVC
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"LoginSignup" bundle:nil];
LoginSignupVC *loginViewController = (LoginSignupVC *)[storyboard instantiateInitialViewController];
// setup the LoginSignupVC inside of a UINavigation Controller
UINavigationController *nav = [[UINavigationController alloc]
initWithRootViewController:loginViewController];
///////////////////////////////////////////////////////////////
// Set the LoginSignupVC's delegate to self
loginViewController.delegate = self;
// Set the Login View Controller's frame
loginViewController.view.frame = self.view.bounds;
// Add login screen as a subview and as a child view controller
[self.view addSubview:loginViewController.view];
[self addChildViewController:loginViewController];
[loginViewController didMoveToParentViewController:self];
// Present the log in view controller
//[self presentViewController:nav animated:YES completion:nil]; // Why doesn't this work? Generates -> Warning: Attempt to present <UINavigationController: 0x7fadf1e43020> on <MainTBC: 0x7fadf1f61600> whose view is not in the window hierarchy!
[self.view.window.rootViewController presentViewController:nav
animated:YES
completion:nil];
///////////////////////////////////////////////////////////////
}
}
I then dismiss the UINavigationController through the use of a delegate method as below:
- (void) dismissLoginSignup:(LoginSignupVC *)controller {
// Animate out the category chooser
[UIView animateWithDuration:0.5 animations:^{
// Dissolve the login screen away
[controller.view setAlpha:0];
} completion:^(BOOL finished) {
// Remove login screen as a child view controller
[controller willMoveToParentViewController:nil];
[controller.view removeFromSuperview];
[controller removeFromParentViewController];
}];
}
My question is whether this an acceptable approach to managing the display of a Login/Signup View Controller. I seem to like it better than replacing the RootViewController through the use of the AppDelegate.
As a further question, am I implementing anything incorrectly or extraneously? It displays and works just fine when tested, but I'm relatively new with iOS.