I have several UIViewController
s that I present programmatically with modalPresentationStyle = .fullScreen
. My stack of UIViewController
s looks like this:
ViewControllerA -> ViewControllerB -> ViewControllerC -> ViewControllerD
What I want to do is dismiss ViewControllerB from ViewControllerD (by clicking a button) so the stack now looks like this:
ViewControllerA -> ViewControllerC -> ViewControllerD
What I tried:
I tried registering a NotificationCenter
listener in ViewControllerB and then posting a notification from ViewControllerD to dismiss ViewControllerB, but that ended up dismissing ViewControllerD.
I tried nesting all the UIViewController
s in a UINavigationController
and popping ViewControllerB in ViewControllerD like this:
if let viewController = navigationController?.viewControllers.first(where: {$0 is ViewControllerB}) {
navigationController?.popToViewController(viewController, animated: false)
}
But that also ended up just popping ViewControllerD.
I tried this:
self.presentingViewController?.presentingViewController?.dismiss(animated: false, completion: nil)
But the problem is you end up dismissing ViewControllerB and ViewControllerC too. I want to just dismiss ViewControllerB and leave the other UIViewController
s as they are.
For clarification, I tried both using UINavigationController and just pushing modals one on top of one another. I don't mind either pattern, as long as I can on-demand destroy UIViewControllers that aren't currently visible, without affecting the chain of the other UIViewControllers in the order they were presented/pushed.
ViewControllerA -> ViewControllerB -> ViewControllerC -> ViewControllerD
It's a stack if you use UINavigationController
and push
action. Then you had an array of view controllers that are held by NavigationController.
However, in the scenario above, you're using present
rather than push
, because I saw the modalPresentationStyle
property here. presentViewController:animated:completion: works differently. You can imagine that push
is a kind of hierarchical horizontal, and present
, on the other hand, is a hierarchical vertical. UIKit allows you to present a single view controller on the current view controller at a time:
vcD above vcC above vcB above vcA
You can simply see the dependencies here since each controller that has a higher layer depends on the lower one. So, whenever you want to break a node
, all nodes from this node to the end will be broken too. i.e, dismiss vcB
and also dismiss vcC
-> vcD
. etc
Update If that's the case as you mentioned, you can try this:
if let indexToRemove = navigationController?.viewControllers.firstIndex(where: { $0 is viewControllerB }) {
navigationController?.viewControllers.remove(at: indexToRemove)
let remainControllers = navigationController?.viewControllers ?? []
navigationController?.setViewControllers(remainControllers, animated: false)
}