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

IosSwiftUiviewcontrollerNavigation

Ios Problem Overview


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?

Ios Solutions


Solution 1 - Ios

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 - Ios

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 - Ios

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 - Ios

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 - Ios

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.

Solution 6 - Ios

Use this code for dismiss presented viewcontrollers and pop to navigation rootviewcontroller swift 4

// MARK:- Dismiss and Pop ViewControllers
func dismissPopAllViewViewControllers() {
    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 7 - Ios

Swift 5.4:

self.navigationController?.popToRootViewController(animated: true)

Solution 8 - Ios

Pops all the view controllers on the stack except the root view controller and updates the display.

func popToRootViewController(animated: Bool)

But if you want to go to specific controller just use the below function.

func popToViewController(UIViewController, animated: Bool)

Pops view controllers until the specified view controller is at the top of the navigation stack.

Solution 9 - Ios

To achieve what you want, modify your navigation stack, then do popViewController.

let allControllers = NSMutableArray(array: navigationController!.viewControllers)
let vcCount = allControllers.count
for _ in 0 ..< vcCount - 2 {
    allControllers.removeObject(at: 1)
}
// now, allControllers[0] is root VC, allControllers[1] is presently displayed VC. write back to nav stack
navigationController!.setViewControllers(allControllers as [AnyObject] as! [UIViewController], animated: false)
// then pop root VC
navigationController!.popViewController(animated: true)

See this for the way to further manipulate the navigation stack. If your topmost VC is modal, dismiss it first before the code above.

Solution 10 - Ios

Create an Unwind Segue (You can find it at https://developer.apple.com/library/archive/featuredarticles/ViewControllerPGforiPhoneOS/UsingSegues.html copyright of Apple Inc.)

> Unwind segues let you dismiss view controllers that have been > presented. You create unwind segues in Interface Builder by linking a > button or other suitable object to the Exit object of the current view > controller. When the user taps the button or interacts with the > appropriate object, UIKit searches the view controller hierarchy for > an object capable of handling the unwind segue. It then dismisses the > current view controller and any intermediate view controllers to > reveal the target of the unwind segue.

To create an unwind segue

  1. Choose the view controller that should appear onscreen at the end of an unwind segue.

  2. Define an unwind action method on the view controller you chose.

>The Swift syntax for this method is as follows:

@IBAction func myUnwindAction(unwindSegue: UIStoryboardSegue)

The Objective-C syntax for this method is as follows:

- (IBAction)myUnwindAction:(UIStoryboardSegue*)unwindSegue

3. Navigate to the view controller that initiates the unwind action.

  1. Control-click the button (or other object) that should initiate the unwind segue. This element should be in the view controller you want to dismiss.

  2. Drag to the Exit object at the top of the view controller scene.

https://developer.apple.com/library/archive/featuredarticles/ViewControllerPGforiPhoneOS/Art/segue_unwind_linking_2x.png

  1. Select your unwind action method from the relationship panel.

You must define an unwind action method in one of your view controllers before trying to create the corresponding unwind segue in Interface Builder. The presence of that method is required and tells Interface Builder that there is a valid target for the unwind segue.

Solution 11 - Ios

In case anyone looking for an Objective-C implementation of the question's answer,

[self.view.window.rootViewController dismissViewControllerAnimated:true completion:nil];

Solution 12 - Ios

 func  dismiss_all(view: UIView){
   view.window!.rootViewController?.dismiss(animated: true, completion: nil)
    
 }

Solution 13 - Ios

May be what you are looking for is unwind segue.

> Unwind segues give you a way to "unwind" the navigation stack back > through push, modal, popover, and other types of segues. You use > unwind segues to "go back" one or more steps in your navigation > hierarchy.

Link to documentation: https://developer.apple.com/library/archive/technotes/tn2298/_index.html

Solution 14 - Ios

The best and prefered way to do this is to create an unwind segue. Just follow this documentation https://developer.apple.com/library/archive/featuredarticles/ViewControllerPGforiPhoneOS/UsingSegues.html. It can de done in code or through the interface builder.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionByothView Question on Stackoverflow
Solution 1 - IosAgent SmithView Answer on Stackoverflow
Solution 2 - IosSandip GillView Answer on Stackoverflow
Solution 3 - IosPathak AyushView Answer on Stackoverflow
Solution 4 - IosSyed Qamar AbbasView Answer on Stackoverflow
Solution 5 - IosShawn FrankView Answer on Stackoverflow
Solution 6 - IosFaris MuhammedView Answer on Stackoverflow
Solution 7 - IosMakwan BarzanView Answer on Stackoverflow
Solution 8 - IosMuhammad ShauketView Answer on Stackoverflow
Solution 9 - IosbeshioView Answer on Stackoverflow
Solution 10 - IosSrinath ShahView Answer on Stackoverflow
Solution 11 - IosFrostmourneView Answer on Stackoverflow
Solution 12 - IosSoftlabsindiaView Answer on Stackoverflow
Solution 13 - IosSrinath ShahView Answer on Stackoverflow
Solution 14 - IosCaseyView Answer on Stackoverflow