12

How to dismiss 2 view controllers in Swift iOS?

Below is my code.

@IBAction func backButtonTapped(sender: AnyObject) {
    self.presentingViewController
        .presentingViewController
        .dismissViewControllerAnimated(true, completion: nil)
}
Cœur
  • 32,421
  • 21
  • 173
  • 232
viju
  • 81
  • 2
  • 3
  • 14

4 Answers4

14

There's special unwind segue for that purpose, it is intended to roll back to certain view controller in stack.

Let's call the topmost controller (where you go from) as source and the controller in stack (which you want to roll back to top) as destination.

  1. create IBAction in destination to be triggered on unwind segue:

    @IBAction func myUnwindAction(segue: UIStoryboardSegue) {}

it can be empty.

  1. in source controller create an unwind segue by dragging from the controller icon to exit one, it will find the action you created at the step 1. Call the segue unwind.

  2. now you can issue that segue from code with regular

    performSegueWithIdentifier("unwind", sender: nil)

I described how to issue unwind segue from code. For buttons unwind segues can be created in IB directly by dragging a button to exit icon.

Also check this discussion for more info: How to perform Unwind segue programmatically?

Community
  • 1
  • 1
Mixaz
  • 3,749
  • 25
  • 51
  • When I do this, I get a runtime error, "Receiver has no segue with identifier" – peacetype Nov 08 '15 at 22:55
  • 3
    This tutorial here might help as well: https://medium.com/@mimicatcodes/create-unwind-segues-in-swift-3-8793f7d23c6f – Mattk90 Oct 25 '17 at 23:02
  • brilliant i got the error no seg with identifier unwind but in the end I just rightdraged the button to the exit on the top and removed the perform code i had in the button before and worked perfect thank you – Tony Merritt Nov 10 '18 at 01:03
  • Great answer. But how to avoid blinking of screens that being dismissed during ``unwind`` action? – Volodymyr Kulyk Jul 03 '20 at 09:39
  • This is the correct answer, and the tutorial link from @Mattk90 is easy to follow if you are confused by any of the steps. – iOS_Mouse Dec 18 '20 at 19:34
14

Swift 3+ version. You can dismiss two view controllers at a time in Swift 3 with this below code.

func dismissTwoViews() {
    self.presentingViewController?
        .presentingViewController?.dismiss(animated: true, completion: nil)
}

Swift 4+ version. just we need pop particular view controller use this extension

extension UINavigationController {

func popToViewController(ofClass: AnyClass, animated: Bool = true) {
    if let vc = viewControllers.filter({$0.isKind(of: ofClass)}).last {
        popToViewController(vc, animated: animated)
    }
}

func popViewControllers(viewsToPop: Int, animated: Bool = true) {
    if viewControllers.count > viewsToPop {
        let vc = viewControllers[viewControllers.count - viewsToPop - 1]
        popToViewController(vc, animated: animated)
    }
}

}

And use like this in your view controller class

for controller in self.navigationController!.viewControllers as 
    Array {
                  if controller.isKind(of: 
    yourPopControllerName.self) {

   self.navigationController?.isNavigationBarHidden = false
                                _ =  
self.navigationController!.popToViewController(controller, 
 animated: false)
                                    break
                                }
                            }
  • 3
    Hm, this code looks exactly the same as posted in the question. What is the difference then? In Swift2 it dismissed only one controller, while in Swift3 it closes both? – Mixaz Oct 26 '17 at 10:07
  • @Mixaz I just tested on Swift 2.2 + iOS 8.1 (Xcode 7.3) and the code from the question was already working. So the difference can be either from an even older Swift version (**very unlikely!**) or actually from an older iOS version (like 8.0 or 7.x). – Cœur Sep 18 '18 at 13:40
2

You can only dismiss one view controller at a time. Try this

@IBAction func backButtonTapped(sender: AnyObject) {
        self.presentingViewController?.dismissViewControllerAnimated(true, completion: {
            let secondPresentingVC = self.presentingViewController?.presentingViewController;
            secondPresentingVC?.dismissViewControllerAnimated(true, completion: {});
        });
}
Stefan Iarca
  • 152
  • 1
  • 7
0

Swift 4:

Created an extension for UIViewController that can pop UIViewControllers in NavigationController stack depending in supplied number of times

extension UIViewController {

    func pop(numberOfTimes: Int) {
        guard let navigationController = navigationController else {
            return
        }
        let viewControllers = navigationController.viewControllers
        let index = numberOfTimes + 1
        if viewControllers.count >= index {
            navigationController.popToViewController(viewControllers[viewControllers.count - index], animated: true)
        }
    }
}
  • I think pop(numberOfTimes) seems to be misleading in terms of readability. How about `pop(numberOfViewControllers: Int)` – Jojo Narte Jan 29 '19 at 14:10