Reputation: 3629
My app is instantiated with my login screen as the initial VC. When the user successfully logs in I instantiate a navigation controller and set the homeVC as the root view controller. From any page in the app once logged in a user may access their "my profile" information, as well as logout.
What is the best way to transition "back" to the login view controller? I'd like to ensure any VC's are removed from memory but because the login VC exists outside of the navigation controller I cannot simply jump back to the root view controller.
Any guidance is appreciated.
Upvotes: 1
Views: 1356
Reputation: 62686
Short answer, if you get from the login UI to the app's main UI by setting the window's root, then that's a good way to get back.
// in some view controller in your app when you need to change to the login UI
UIStoryboard *storyboard = [self storyboard];
UIViewController *vc = [storyboard instantiateViewControllerWithIdentifier:@"MyLoginVCIdentifier"];
UIWindow *window = [UIApplication sharedApplication].delegate.window;
window.rootViewController = vc;
Longer Answer, I sometimes use a view controller whose only job is to manage this, calling it LaunchViewController
.
In my main.storyboard, I create an instance of LaunchViewController
and set "Is Initial View Controller" to true.
This VC needs no UI, since it's only job is to replace itself as soon as it appears. However, since I don't even want a split-second flash after my LaunchScreen.storyboard, I sometimes do this to overlay this vc's view with the launch storyboard view, but this part is optional....
// LaunchViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
UIStoryboard *storyboard = [self.class storyboardWithKey:@"UILaunchStoryboardName"];
UIViewController *vc = [storyboard instantiateViewControllerWithIdentifier:@"LaunchVC"];
[self.view addSubview:vc.view];
}
// a convenience method to get a storyboard from the bundle by key
+ (UIStoryboard *)storyboardWithKey:(NSString *)key {
NSBundle *bundle = [NSBundle mainBundle];
NSString *storyboardName = [bundle objectForInfoDictionaryKey:key];
return [UIStoryboard storyboardWithName:storyboardName bundle:bundle];
}
Back to your question, my LaunchViewController provides a method that presents (with an animation of your choosing) a main storyboard view controller given it's storyboard identifier...
// LaunchViewController.m
+ (void)presentUI:(NSString *)identifier {
UIStoryboard *storyboard = [self storyboardWithKey:@"UIMainStoryboardFile"];
UINavigationController *vc = [storyboard instantiateViewControllerWithIdentifier:identifier];
UIWindow *window = [UIApplication sharedApplication].delegate.window;
window.rootViewController = vc;
[UIView transitionWithView:window
duration:0.3
options:UIViewAnimationOptionTransitionCrossDissolve
animations:nil
completion:nil];
}
With that, we can give the LaunchViewController
any number of public methods like...
+ (void)presentLoginUI {
[self presentUI:@"IdentifierOfMyLoginViewController"];
}
+ (void)presentMainAppUI {
[self presentUI:@"IdentifierOfMyMainAppViewController"];
}
Since the system window has the only pointer to the root view controller, and you replace that pointer in presentUI:
, ARC will clean up the whole discarded UI for you.
Upvotes: 3