Development environment:
- Swift Language Version: Swift 5
- Xcode: Version 10.2.1 (10E1001)
- Deployment Target: 12.0
Today I will introduce to you a simple and common way in handling the operation of logging in and out between screens in the iOS App. That’s the Swap the Root View Controller.
Step 1: Initialize the login / main screen
In turn, we will create 2 login and main screens as shown below:
Next we declare loginViewController and mainViewController in the UIStoryboard extension:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | extension UIStoryboard { static var main: UIStoryboard { return UIStoryboard(name: "Main", bundle: nil) } } extension UIStoryboard { var loginViewController: LoginViewController { guard let vc = UIStoryboard.main.instantiateViewController(withIdentifier: "LoginViewController") as? LoginViewController else { fatalError("LoginViewController couldn't be found in Storyboard file") } return vc } var mainViewController: MainViewController { guard let vc = UIStoryboard.main.instantiateViewController(withIdentifier: "MainViewController") as? MainViewController else { fatalError("MainViewController couldn't be found in Storyboard file") } return vc } } |
Step 2: Create a singleton App class
Here we use UserDefaults to store bool values for the purpose of checking the login / logout of the user.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | final class App { static var shared = App() var window: UIWindow! var mainNavigationController: UINavigationController! var loginViewController: UIViewController! func startInterface() { // MARK: Initial MainNavigationController and MainViewController let mainNavigationController = UINavigationController() let mainViewController = UIStoryboard.main.mainViewController // MARK: Initial LoginViewController loginViewController = UIStoryboard.main.loginViewController if UserDefaults.standard.bool(forKey: "LOGGED_IN") { // check whether user logged or not window.rootViewController = mainNavigationController } else { window.rootViewController = loginViewController } window.makeKeyAndVisible() } } |
Step 3: Initialize the switchBackToLogin () and switchLoginToMain ()
The switchBackToLogin () function changes rootViewController = loginViewController when the user presses the logout button at the MainViewController screen.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | func swipeBackToLogin() { let snapShot = window.snapshotView(afterScreenUpdates: true) if let snapShot = snapShot { loginViewController.view.addSubview(snapShot) } window.rootViewController = loginViewController UIView.animate(withDuration: 0.3, animations: { snapShot?.layer.opacity = 0 snapShot?.layer.transform = CATransform3DMakeScale(1, 1, 1) }) { finished in snapShot?.removeFromSuperview() } } |
The switchLoginToMain () function changes rootViewController = mainNavigationController when the user presses the login button at the loginViewController screen.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | func swipeLoginToMain() { let snapShot = window.snapshotView(afterScreenUpdates: true) if let snapShot = snapShot { mainNavigationController.view.addSubview(snapShot) } window.rootViewController = mainNavigationController UIView.animate(withDuration: 0.3, animations: { snapShot?.layer.opacity = 0 snapShot?.layer.transform = CATransform3DMakeScale(1, 1, 1) }) { finished in snapShot?.removeFromSuperview() } } |
Step 4: Complete
In AppDelegate.cs , we assign App.shared.window = window and call func startInterface () in singleton App.
1 2 3 4 5 6 7 8 9 10 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { window = UIWindow(frame: UIScreen.main.bounds) if let window = window { App.shared.window = window App.shared.startInterface() } return true } |
In LoginViewController , we set the bool value in UserDefaults to true when the user presses the login button and invokes the switchLoginToMain () function so that the screen switches to MainViewController .
1 2 3 4 5 6 7 8 9 10 11 12 | final class LoginViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() } @IBAction func handleLoginButtonTapped(_ sender: Any) { UserDefaults.standard.set(true, forKey: "LOGGED_IN") App.shared.switchLoginToMain() } } |
In MainViewController , we set the bool value in UserDefaults to false when the user presses the logout button and calls the switchBackToLogin () function to return to the LoginViewController screen.
1 2 3 4 5 6 7 8 9 10 11 12 13 | final class MainViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() navigationItem.title = "Main" } @IBAction func handleLogoutButtonTapped(_ sender: Any) { UserDefaults.standard.set(false, forKey: "LOGGED_IN") App.shared.switchBackToLogin() } } |
And this is the result: