Search code examples
iosswiftxcodeuinavigationcontroller

Cannot pop back in Navigation controller from Alert completion:


Swift 4, XCode 9.4

I cannot pop back to the root of the stack in the completion of (or even near) a UIAlertController.

The requirement is to show the user a confirmation and then directly transition back to the 'home' page. When I try I always get something like :

popToViewController:transition: called on <UINavigationController 0x7fc4fe85f000> while an existing transition or presentation is occurring; the navigation stack will not be updated.

I understand the concept I suppose. The UIAlertController is in control, or the nav controller is not sufficiently in control to pop back. Ok makes some sense since I am in the completion. But I don't see how to trigger my transition without being in there.

@IBAction func doneAction(_ sender: Any) {

    if verifyDoneProperly() {

        let alert = UIAlertController(title: "Complete", message: "Good Job", preferredStyle: UIAlertControllerStyle.alert)
        alert.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.default, handler: nil))
        self.present(alert, animated: true, completion: { 

            if let nav = self.navigationController {
                nav.popToViewController(select, animated: true)
            }
        })
    }
}

FWIW, It doesn't work when I specify the view controller either.

I have read carefully through this answer but nothing there is really going to help me (AFAIK).

The only thing I can really think to do is to send a message to the root controller and have it display the alert after having transitioned back (Perhaps checking for a flag in viewWillAppear)

There must surely be a correct way to do this. Can anyone suggest something?

Important Note: I cannot use segues here although I do have a storyboard. The transition to the 'worker' view controller is done programmatically and chosen based on the current state.


Solution

  • I'm not sure it's the best idea to pop a view controller while it's still presenting something else. And the completion of present is not executed after the view controller is dismissed, only after it has finished presentation (i.e., become visible on the screen).

    You can pop your view controller in the handler of your OK action — which will be called after your view controller is no longer presenting the alert.

    alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { (_) in
        self.navigationController?.popToViewController(select, animated: true)
    }))