37

I have a root view controller that has a button that when the user pushes it, another view controller is presented.

This second controller has a dismiss option that just comes back to the root view controller and a button that when the user touches it dismisses the current view controller so it goes back to the root view controller for a second and presents another one.

Going to the first controller I use:

let vc = FirstController()
self.present(vc, animated: true, completion: nil)

And when in the other view controller I select the button that only dismisses I do this.

self.dismiss(animated: true, completion: nil)

So for the second controller that needs to dismiss and present another one I have tried the following:

self.dismiss(animated: true, completion: {
    let vc = SecondController()
    self.present(vc, animated: true, completion: nil)
})

But I get an error:

Warning: Attempt to present <UINavigationController: 0xa40c790> on <IIViewDeckController: 0xa843000> whose view is not in the window hierarchy!

pkamb
  • 33,281
  • 23
  • 160
  • 191
ravelinx
  • 1,557
  • 4
  • 18
  • 26

2 Answers2

97

The error occurs because you are trying to present SecondController from FirstController after you have dismissed FirstController. This doesn't work:

self.dismiss(animated: true, completion: {
    let vc = SecondController()

    // 'self' refers to FirstController, but you have just dismissed
    //  FirstController! It's no longer in the view hierarchy!
    self.present(vc, animated: true, completion: nil)
})

This problem is very similar to a question I answered yesterday.

Modified for your scenario, I would suggest this:

weak var pvc = self.presentingViewController

self.dismiss(animated: true, completion: {
    let vc = SecondController()
    pvc?.present(vc, animated: true, completion: nil)
})
Community
  • 1
  • 1
Mike Taverne
  • 9,156
  • 2
  • 42
  • 58
0

Only the presenting view controller (Root) can dismiss its presented view controller (First or Second). So you need to call dismiss(animated:completion:) inside the Root view controller's class, not inside any other one:

class RootViewController: UIViewController {
  func buttonTapped() {
    let vc = FirstViewController()
    vc.delegate = self
    present(vc, animated: true)
  }
}

extension RootViewController: FirstViewControllerDelegate {
  func firstDidComplete() {
    dismiss(animated: true) {
      let vc = SecondViewController()
      vc.delegate = self
      present(vc, animated: true)
    }
  }
}

extension RootViewController: SecondViewControllerDelegate {
  func secondDidComplete() {
    dismiss(animated: true) {
      let vc = ThirdViewController()
      present(vc, animated: true)
    }
  }
}

// and so on

If FirstViewController presents other view controller and you want its dismissal animation, implement FirstViewController as follows:

extension FirstViewController: OtherViewControllerDelegate {
  func otherDidComplete() {
    dismiss(animated: true) {
      self.delegate?.firstDidComplete()
    }
  }
}
Roman Aliyev
  • 224
  • 2
  • 7