Dismissing a Presented View Controller
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
When a view controller is presented modally in UIKit, dismissing it is normally straightforward: call dismiss(animated:completion:). The part that confuses many developers is not the method itself, but which controller should call it and how the modal hierarchy affects the result.
The rule of thumb is simple. Dismiss the presented flow from somewhere inside that flow, or from the presenting controller if you still have a clean reference to it.
Dismiss from the Presented Controller
The most common pattern is for the modal screen to dismiss itself after the user taps a close button.
This works because the presented controller can ask UIKit to dismiss the modal presentation it belongs to. In most cases, that is the cleanest approach.
Dismiss from the Presenting Controller
The presenting controller can also dismiss the modal later if it still controls the flow.
That can be useful when an external event should close the modal, such as a login finishing or a timeout expiring.
Navigation Controllers Change What Is Actually Presented
One common source of confusion is presenting a UINavigationController whose root is your content controller. In that setup, the navigation controller is the presented object, even though the user sees the root screen inside it.
That means dismissing from the root controller still works, but conceptually the whole modal stack is being dismissed.
If editor later calls dismiss(animated: true), UIKit dismisses the presented navigation controller and everything inside it.
Use Completion for Follow-Up Work
If something must happen only after the dismissal animation finishes, use the completion closure.
That is the right place for cleanup that depends on the modal no longer being visible, such as triggering a refresh on the underlying screen.
Understand Dismiss vs Pop
Another frequent confusion is mixing modal dismissal with navigation popping. If a screen was pushed onto a navigation stack, use navigationController?.popViewController(animated: true). If it was presented modally, use dismiss.
The visible UI can look similar, but the ownership model is different:
- '
dismisscloses a modal presentation' - '
popViewControllermoves back inside a navigation stack'
Knowing how the screen was shown tells you how it should be removed.
Common Pitfalls
The most common mistake is calling popViewController for a modally presented screen, or calling dismiss for a screen that was only pushed.
Another issue is forgetting that a navigation controller may be the presented object, not the root content controller you created first.
It is also easy to retain stale references to a dismissed controller and then try to dismiss it again later. That usually indicates the presentation flow should be simplified.
Finally, when dismissal needs to trigger later work, put that logic in the completion closure instead of assuming the animation has already finished.
Summary
- Use
dismiss(animated:completion:)to close modally presented view controllers. - A presented controller can usually dismiss itself cleanly.
- If the modal is wrapped in a navigation controller, dismissing the root closes the full presented stack.
- Use
popViewControlleronly for navigation-stack pushes, not modal presentations. - Put post-dismiss logic in the completion closure when timing matters.

