I have having a lot of trouble handling the login flow of my iOS app. An image of the storyboard I am trying to achieve is below
I am trying to achieve an optional login screen which is presented only when a user first opens the app and has not logged in. Currently, I have the Tab Bar Controller set as the root view controller. I can not figure out how to handle swapping between these view controllers, however.
I have tried to simply push the login screen with the following code. However, it does not work. I believe the problem that a tab bar controller is not allowed to push new view controllers.
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
//stuff
if userLoggedIn {
// Do nothing
} else {
//get access to login view
var storyboard = UIStoryboard(name: "Main", bundle: nil)
var viewController = storyboard.instantiateViewControllerWithIdentifier("signupView") as UIViewController;
// Then push login view
var rootViewController = self.window!.rootViewController as UITabBarController;
rootViewController.pushViewController(viewController, animated: true)
}
// Override point for customization after application launch.
return true
}
Is there a way to switch view controllers without pushing within a navigation controller? Any advice on how to handle this sort of login flow would be greatly appreciated.
I achieve this with a "LaunchViewController" that determines if it should present the Login view or the main navigation controller.
Mark the launch view your initial view in the storyboard and write the logic in there to determine which to present. This process is often very quick and unnoticeable to the user.
UPDATE:
As mentioned in my comment I've gone a different direction. Now in the App Delegate's application(application:didFinishLaunchingWithOptions:)
method I perform the logic necessary to determine which view should be the rootViewController
and set it there using the following.
extension AppDelegate {
enum LaunchViewController {
case Login, Dashboard
var viewController: UIViewController {
switch self {
case .Login: return StoryboardScene.Login.LoginScene.viewController()
case .Dashboard: return StoryboardScene.Dashboard.initialViewController()
}
}
/// Sets `UIWindow().rootViewController` to the appropriate view controller, by default this runs without an animation.
func setAsRootviewController(animated animated: Bool = false) {
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let window = appDelegate.window!
let launchViewController = viewController
log.info?.message("Setting \(launchViewController.dynamicType) as rootViewController")
if let rootViewController = window.rootViewController where rootViewController.dynamicType != launchViewController.dynamicType && animated {
let overlayView = UIScreen.mainScreen().snapshotViewAfterScreenUpdates(false)
launchViewController.view.addSubview(overlayView)
UIView.animateWithDuration(0.3, animations: {
overlayView.alpha = 0.0
},
completion: { _ in
overlayView.removeFromSuperview()
});
}
window.rootViewController = launchViewController
window.restorationIdentifier = String(launchViewController.dynamicType)
if window.keyWindow == false {
window.makeKeyAndVisible()
}
}
}
}
Note that StoryboardScene
is not a default type, I am using https://github.com/AliSoftware/SwiftGen to generate that.
My App Delegate method looks something like this.
if window == nil {
window = UIWindow(frame: UIScreen.mainScreen().bounds)
}
if isRestoringState == false {
if let _ = lastUsedAccount {
LaunchViewController.Dashboard.setAsRootviewController()
} else {
LaunchViewController.Login.setAsRootviewController()
}
}
UPDATE with Logout method for Comment
func handleLogout(notification: NSNotification) {
LaunchViewController.Login.setAsRootviewController(animated: true)
lastUsedAccount = nil
}
Here is what i did and it works fine :
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
if (!AppData.sharedInstance.loggedIn) {
let signInNavigation = UIStoryboard(name: "Main", bundle: NSBundle.mainBundle()).instantiateViewControllerWithIdentifier("SignInNavigationControllerIdentifier") as? UINavigationController
self.window!.rootViewController = signInNavigation;
}
return true
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With