4

I am relatively new to IOS development and come from an Android background. I am looking for a way to return to my original view controller once the user logs out.

This post How can I go back to the initial view controller in Swift? recommends that I should use an unwind segue.

However, the user session in my application can expire at any moment and from any view controller. This requires me to create a rewind segue from every view controller to the root view controller. Moreover, it leads to duplication of code as each view controller would need to identify its own specific segue ID.

Originally, I was hoping to subclass UIViewController and make a CustomViewController upon which all my other ProfileViewController, LoginViewController would then subclass.

CustomViewController would provide helper methods such as func logOut(). Is there a way to do this, perhaps via some generic unwind segue? One that is automatically "inherited" in the future?

AlanSTACK
  • 5,525
  • 3
  • 40
  • 99

2 Answers2

3

You cant have generic unwind segue. You cant inherit the storyboard properties of ViewController including the segue associated with ViewController. But you dont need a generic segue to solve your problem.

You can have a BaseViewController and all your other View Controllers will extend from BaseViewController. You can add your logic to verify if the user is still logged in in your BaseViewController (I cant write code for that as I have not seen your code base).

If the user is no longer logged in then you can simply call

class BaseViewController : UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        //implement your logic to monitor if user is still logged in if user not logged in simply call
        self.logOut()
    }

    func logOut() {
       //each child view controller will override and handle log out condition specifically for that ViewController
    }
}

Finally to load the initial ViewController you can simply say pop all viewController on top of it. Assuming your initialViewController is rootViewController of your app you can simply modify your logic in BaseViewController as

   override func viewDidLoad() {
        super.viewDidLoad()
        //implement your logic to monitor if user is still logged in if user not logged in simply call
        self.logOut()
        UIApplication.shared.keyWindow?.rootViewController?.navigationController?.popToRootViewController(animated: true)
    }

Issue with the approach:

Based on your question description I believe your initial view controller is kept in the ViewController stack and you simply unwind to that initial ViewController on logout.

Though this approach works, it has three issues

  1. Initial ViewController is unnecessarily kept in memory while it never reappears until user logs out, so you can actually get rid of it once user logs in and bring it back in once user logs out.

  2. If the user logs in and quits the app and restarts the app, app will load the initial View controller, but if the user is already logged in why would you even show initial view controller to him again??

  3. Because you are pushing other VCs on top of initial ViewController, that also means that user can simply keep hitting back button and come back to initial viewController which does not make sense, because how come user tapping on back button has anything to do with user logged in state ?? Isnt it??

Whats the better solution then ?

Change the root view controller of the app on app launch.

Open your AppDelegate and

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
   //check if user is logged in

   guard let window = UIApplication.shared.keyWindow else {
        return
   }

   if (userIsLoggedIn) {
      //load view controller that you wanna show after login lets say Home
      let homeVC = //instantiate view controller from story board
      UIView.transition(with: window, duration: 0.3, options: .transitionCrossDissolve, animations: {
            window.rootViewController = homeVC
        }, completion: { completed in
            // maybe do something here
        })
   }
   else {
       //load initial controller 
      let initialVC = //instantiate view controller from story board
      UIView.transition(with: window, duration: 0.3, options: .transitionCrossDissolve, animations: {
            window.rootViewController = initialVC
        }, completion: { completed in
            // maybe do something here
        })
   }
}

Finally, if user isnt logged in and u end up loading initial VC and once user logs in your initial VC, you can use the code which I wrote above to change root VC

      let initialVC = //instantiate view controller from story board
      UIView.transition(with: window, duration: 0.3, options: .transitionCrossDissolve, animations: {
            window.rootViewController = initialVC
        }, completion: { completed in
            // maybe do something here
        })
Sandeep Bhandari
  • 19,999
  • 5
  • 45
  • 78
1

If you want to go back to the login view controller, you can set a single rewind (exit) to that view from the immediate next one. And then use the Notification Center to post a notification from anywhere in your app. That “next to login” view observes the notification and performs the rewind segue.

Gabriel
  • 3,319
  • 1
  • 16
  • 21
  • What would happen to the current view though? Lets say I have `LoginVC -> ProfileVC -> CurrentVC` If I initiated a rewind from `ProfileVC to LoginVC` what happens to `CurrentVC`? – AlanSTACK Feb 21 '18 at 17:20