Swift - How to dismiss all of view controllers to go back to root

83,251

Solution 1

Try This :

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

it should dismiss all view controllers above the root view controller.

If that doesn't work than you can manually do that by running a while loop like this.

func dismissViewControllers() {

    guard let vc = self.presentingViewController else { return }

    while (vc.presentingViewController != nil) {
        vc.dismiss(animated: true, completion: nil)
    }
}

It would dismiss all viewControllers until it has a presentingController.

Edit : if you want to dismiss/pop pushed ViewControllers you can use

self.navigationController?.popToRootViewController(animated: true)

Hope it helps.

Solution 2

If you are using Navigation you can use first one or if you are presenting modally you can second one:

For Navigation

self.navigationController?.popToRootViewController(animated: true)

For Presenting modally

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

Solution 3

Hello everyone here is the answer for Swift-4.

To go back to root view controller, you can simply call a line of code and your work will be done.

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

And if you have the splash screen and after that the login screen and you want to go to login screen you can simply append presentedviewcontroller in the above code.

self.view.window?.rootViewController?.presentedViewController!.dismiss(animated: true, completion: nil)

Solution 4

Simply ask your rootViewController to dismiss any ViewController if presenting.

if let appDelegate = UIApplication.shared.delegate as? AppDelegate {
   appDelegate.window?.rootViewController?.dismiss(animated: true, completion: nil)
   (appDelegate.window?.rootViewController as? UINavigationController)?.popToRootViewController(animated: true)
}

Solution 5

The strategy to go back to your initial view controller could vary depending on your view controllers are stacked.

There could be multiple scenarios and depending on your situation, you can decide which approach is the best.

Scenario 1

  • Navigation controller is set as the root view controller
  • Navigation controller sets View Controller A as the root
  • Navigation controller pushes View Controller B
  • Navigation controller pushes View Controller C

This is a straightforward scenario where navigationController?.popToRootViewController(animated:true) is going to work from any view controller and return you back to View Controller A

Scenario 2

  • Navigation controller is set as the root view controller
  • Navigation controller sets View Controller A as the root
  • View Controller A presents View Controller B
  • View Controller B presents View Controller C

This scenario can be solved by the answers above self?.view.window?.rootViewController.dismiss(animated: true) and will bring you back to View Controller A

Scenario 3

  • Navigation controller 1 is set as the root view controller
  • Navigation controller 1 sets View Controller A as the root
  • Navigation controller 1 pushes View Controller B
  • View Controller B presents Navigation Controller 2
  • Navigation Controller 2 sets View Controller D as the root
  • Navigation controller 2 pushes View Controller E

Now imagine that you need to go from View Controller E all the way back to A

Using the 2 answers above will not solve your problem this time as popping to root cannot happen if the navigation controller is not on the screen.

You might try to add timers and listeners for dismissing of view controllers and then popping which can work, I think there was an answer like this above with a function dismissPopAllViewViewControllers - I notice this leads to unusual behavior and with this warning Unbalanced calls to begin/end appearance transitions for

I believe what you can do to solve such scenarios is to

  • start by presenting your modal views controllers from the navigation controller itself
  • now you have better control to do what you want

So I would change the above to this architecture first:

  • Navigation controller 1 is set as the root view controller (same)
  • Navigation controller 1 sets View Controller A as the root (same)
  • Navigation controller 1 pushes View Controller B (same)
  • Navigation controller 1 presents Navigation Controller 2 (change)
  • Navigation Controller 2 sets View Controller D as the root (same)
  • Navigation controller 2 pushes View Controller E (same)

Now from View Controller E, if you add this:

let rootViewController = self?.view.window?.rootViewController as? UINavigationController

rootViewController?.setViewControllers([rootViewController!.viewControllers.first!], 
animated: false)

rootViewController?.dismiss(animated: true, completion: nil)

you will be transported all the way back to View Controller A without any warnings

You can adjust this based on your requirements but this is the concept on how you can reset a complex view controller hierarchy.

Share:
83,251
Byoth
Author by

Byoth

I am not good at English :(

Updated on July 05, 2022

Comments

  • Byoth
    Byoth almost 2 years

    I want a my app can go to a first view controller when every time users want it.

    So I want to create a function to dismiss all the view controllers, regardless of whether it is pushed in navigation controllers or presented modally or opened anything methods.

    I tried various ways, but I failed to dismiss all the view controllers certainly. Is there an easy way?

  • Byoth
    Byoth over 6 years
    Thanks. It is completely working for all the presented view controllers, but not working for the pushed view controllers(if root view controller is a navigation controller). so I also reflected together the other opinions that using popToRootViewController and I solved it :)
  • Byoth
    Byoth over 6 years
    Thanks. It is completely working for all the presented view controllers, but not working for the pushed view controllers(if root view controller is a navigation controller). so I also reflected together the other opinions that using popToRootViewController and I solved it :)
  • Syed Qamar Abbas
    Syed Qamar Abbas over 6 years
    Edited answer for you. It will first dismiss all viewController and then pop all viewController if the root is UINavigationController.
  • Agent Smith
    Agent Smith over 6 years
    @Byoth Edited the answer.
  • Sandip Gill
    Sandip Gill almost 6 years
    Erhan Demirci My Please dear
  • somenickname
    somenickname almost 6 years
    This works for me when I don't have self reference to currently presenting window
  • Zahurafzal Mirza
    Zahurafzal Mirza almost 6 years
    What if i want to present view controller..uptill a specific count..from a for loop..say if count is 5 ..then 5 times the same view controller should be presented..is it possible ?
  • Agent Smith
    Agent Smith almost 6 years
    @ZahurafzalMirza you want to present a viewController after popping 5 times or you want to present a single view controller 5 times?
  • Zahurafzal Mirza
    Zahurafzal Mirza almost 6 years
    No i want to present a single view controller 5 times..i have done the coding but only the last one gets presented..can u provide me with an overview of how to do it ?
  • Agent Smith
    Agent Smith almost 6 years
    @ZahurafzalMirza Can you show me the code that you've done?
  • Zahurafzal Mirza
    Zahurafzal Mirza almost 6 years
    Thank you but i managed to do it myself :) i will upload the code and send a link shortly
  • SalmonKiller
    SalmonKiller about 5 years
    Hey, welcome to Stack Overflow! Can you please post an example of creating a segue in addition to excerpts and link to the documentation? Thanks!
  • Srinath Shah
    Srinath Shah about 5 years
    I will add another answer for legibility.
  • Nigel Brown
    Nigel Brown almost 5 years
    Swift 3.0 For Presenting modally self.view.window!.rootViewController?.dismiss(animated: true, completion: nil)
  • Weslie
    Weslie over 4 years
    Thanks a lot, but there is still one issue. for example, if i presented three view controller and call root vc dismiss, then i will see the vc beneath top vc being dismissed in a flash. So, is this the normal way for dismiss to root vc?
  • Agent Smith
    Agent Smith over 4 years
    I haven't found any solution to this other than dismissing without animation. It doesn't seem to work like popViewController but it does the work.
  • Markinson
    Markinson over 4 years
    The exclamation point after window on 'For Presenting Modally' was making the app crash for me. so I did self.view.window?.rootViewController?.dismissViewControllerA‌​nimated(false, completion: nil)
  • Sandip Gill
    Sandip Gill over 4 years
    @Markinson Yes '!' and '?' both are used to define that the variable could be nil or not. If you declare it as '!' and then variable could not be nil and if its nil then it will cause a crash. '?' prevents app from crashing.
  • sɐunıɔןɐqɐp
    sɐunıɔןɐqɐp over 4 years
    From Review: Hi, while links are great way of sharing knowledge, they won't really answer the question if they get broken in the future. Add to your answer the essential content of the link which answers the question. In case the content is too complex or too big to fit here, describe the general idea of the proposed solution. Remember to always keep a link reference to the original solution's website. See: How do I write a good answer?
  • khjfquantumjj
    khjfquantumjj over 4 years
    this answer is duplicate to: stackoverflow.com/a/47322468/5318223
  • Vyachaslav Gerchicov
    Vyachaslav Gerchicov about 4 years
    the question doesn't mention using of segues which have their own troubles
  • Julian Silvestri
    Julian Silvestri about 4 years
    you should be careful about forcing the window. If the window is nil, app will crash. Making it optional will prevent it from crashing