44

So I have a login view, after successful login it goes to the first view of a navigation controller, then the user can go deeper to a settings view and then to a logout view. This logout should take the user back to the login view (which is not part of the navigation controller). It works with this code:

let loginViewController = self.storyboard!.instantiateViewControllerWithIdentifier("Login") as? LoginViewController
self.navigationController!.pushViewController(loginViewController!, animated: true)

But the login view displays the navigation bar at the top, which it shouldn't do, maybe there is something other than self.navigationController!.pushViewController that I should be using?

matt
  • 2,312
  • 5
  • 34
  • 57

6 Answers6

89

SWIFT: You should use an unwind segue.

  1. First of all, put the following line in your FirstViewController:

    @IBAction func prepareForUnwind(segue: UIStoryboardSegue) {
    
    }
    

    The function actually doesn't have any code inside it.


  1. Now, go to your storyboard and create an unwind segue for LogoutViewController by control-dragging from the yellow button to the Exit button. Like this:

control-dragging in action

  1. Select the unwind segue created for FirstViewController.

  2. Change the segue identifier:

selected segue


changing the identifier of the segue

  1. Go to the code of LogoutViewController and just call the unwind segue normally:

    self.performSegueWithIdentifier("unwindToViewController1", sender: self)
    

    Swift 4

    self.performSegue(withIdentifier: "unwindToViewController1", sender: self)
    
Tamás Sengel
  • 55,884
  • 29
  • 169
  • 223
Allan Scofield
  • 1,884
  • 18
  • 14
  • 1
    This is definitely the best answer – Canopus Dec 02 '15 at 12:02
  • 1
    Worked flawlessly the first time, which is very rare to happen in a dev's life. This answer is still valid for Xcode 8 and Swift 3. – zeeshan Jan 24 '17 at 19:10
  • Works like a charm! Thanks a lot – Tib Mar 01 '17 at 09:33
  • Perfecto Mondo! – Alex McPherson Mar 10 '17 at 12:56
  • Im stuck in this problem still... how do you tackle this issue when a user logs in, then you set a token in the NSUserdefaults so he does not have to login again and sometime in the future he decides to logout? When I try this approach the "Login" screen is not anymore in the controller stack because I skip this screen in the app start so I can't Unwind to the login screen. Plz help! – Matias Contreras Jul 13 '17 at 16:59
  • great solution! – Jorge Irún Jan 17 '18 at 19:49
  • @MatíasContrerasSelman I am facing the same issue. Plz help if you have solved it – Mamta Jan 22 '18 at 17:46
  • I had to rethink the way the app starts the first time.Tthe way I did it is to programmatically instantiate all the starting screens EVERY time the app loads but programmatically jumping to the main screen without animation in between when the user token is set. This way the Login Screen is always in the stack of views and I can unwind to it when the user press the "logout" button. – Matias Contreras Jan 23 '18 at 20:08
  • In Swift4.2 You should use @IBAction func prepareForUnwindWithSegue(segue: UIStoryboardSegue) { print("Sign Out") } – Arjun Patel Feb 13 '19 at 07:56
  • this is the only answer that worked. You could write a blog for it that comes first on a google search. – thenakulchawla Apr 12 '20 at 05:05
29

If you have a Navigation controller, from your your controller use:

self.navigationController?.popToRootViewControllerAnimated(true)
Rene Ramirez
  • 458
  • 5
  • 7
27

Look into unwind segueing if you are working with storyboards.

You just need to create unwind option in controller, that you want navigate to:

@IBAction func unwindToMe(segue: UIStoryboardSegue){}

Then create segue from storyboard.

And when you need to navigate back, just call the performSegue method with the unwind segue identifier that you just created.

If you want to do it only from code, than you just can write something like:

let loginViewController = self.storyboard?.instantiateViewControllerWithIdentifier("Login")
UIApplication.sharedApplication().keyWindow?.rootViewController = loginViewController

In this case, you will set your app to initial state.

Vasyl Khmil
  • 2,548
  • 1
  • 20
  • 36
18

try it

    self.view.window?.rootViewController?.dismissViewControllerAnimated(true, completion: nil)

This will get you back to the beginning of the application flow.

Updated to Swift 4 (thanks @javaBeast)

    self.view.window?.rootViewController?.dismiss(animated: true, completion: nil) 
andreskwan
  • 1,152
  • 1
  • 13
  • 13
Fco Junior
  • 300
  • 3
  • 7
  • 1
    Worked great for me because I had 3 different views and in-between then I had 2 navigation controllers – Tony Merritt Jun 13 '17 at 12:40
  • 1
    After finding 10 other solutions that didnt work for me, this one finally did, thanks! updated for SWIFT 4: `self.view.window?.rootViewController?.dismiss(animated: true, completion: nil)` – JavaBeast Jun 07 '18 at 08:20
  • The only solution which worked for me in SWIFT 5. Thank you so much ! – Flo Aug 16 '19 at 08:12
1
self.navigationController?.popToRootViewController(animated: true)

is the best option to go to first controller of navigation controller and then dismiss the navigation controller

Mr Zee
  • 87
  • 7
0

I recommend you to make a segue from one ViewController to another, instead of pushing your ViewController like that.

So first, you need to Ctrl + clic from your first ViewController to your login ViewController, and then in the attribute inspector your give it an Identifier.

Then, all you have to do is this :

    self.performSegueWithIdentifier("yourIdentifier", sender: self)

Now, for the navigation bar, I suggest you to remove the navigation controller from the login view, and associate it to your first view. It would remove the navigation bar from your login view.

tmato
  • 71
  • 8
  • I don't believe this works with what he's trying to do... because if you performSegueWithIdentifier, you're adding a new window to the window stacks... not returning to the first view controller.. The best answer would be the answer provided by Allan – Agustin Jul 25 '16 at 01:45