iOS
Swift
ViewController
MobileDevelopment
ProgrammingTips

single function to dismiss all open view controllers

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

In UIKit, "dismiss all open view controllers" sounds like one operation, but it usually hides two different navigation mechanisms: modal presentation and navigation-stack pushing. A useful single function is possible only if you first decide whether you want to dismiss every presented controller, pop a navigation stack back to its root, or do both in a coordinated way.

Dismissing the Entire Modal Presentation Chain

If your app presented several controllers modally, UIKit can collapse the whole modal chain from the presenting root. You do not need to dismiss each controller one by one.

A practical helper is:

swift
1import UIKit
2
3extension UIViewController {
4    func dismissAllPresented(animated: Bool = true, completion: (() -> Void)? = nil) {
5        guard let root = view.window?.rootViewController else {
6            completion?()
7            return
8        }
9
10        root.dismiss(animated: animated, completion: completion)
11    }
12}

Calling dismissAllPresented() from a currently visible controller tells UIKit to dismiss the entire stack of modally presented screens rooted in that window. This is the right answer when your open screens came from present(_:animated:completion:).

It is not the right answer for controllers that were pushed onto a UINavigationController. Those are managed differently.

When a screen was shown with pushViewController, it is part of a navigation stack, not a modal presentation. Dismissing will not unwind that stack. You need to pop instead:

swift
navigationController?.popToRootViewController(animated: true)

That returns the navigation controller to its root, but it does nothing to separate modal flows presented above it. So there is no universal "one dismissal API" that resets every UIKit navigation style by itself.

If your app mainly uses pushed screens, a better helper is explicit about that:

swift
1import UIKit
2
3extension UIViewController {
4    func popToRoot(animated: Bool = true) {
5        navigationController?.popToRootViewController(animated: animated)
6    }
7}

Build a Combined Helper Only If Your App Structure Is Stable

Real apps often mix both patterns. A modal may contain a navigation controller, or a root navigation controller may present a modal flow whose own stack contains several pushed screens.

If you truly want one function to "close everything visible and return to the root state," write a helper that first dismisses modals and then resets the navigation stack:

swift
1import UIKit
2
3extension UIViewController {
4    func closeAllScreens(animated: Bool = true, completion: (() -> Void)? = nil) {
5        guard let root = view.window?.rootViewController else {
6            completion?()
7            return
8        }
9
10        root.dismiss(animated: animated) {
11            if let nav = root as? UINavigationController {
12                nav.popToRootViewController(animated: false)
13            } else if let nav = root.navigationController {
14                nav.popToRootViewController(animated: false)
15            }
16            completion?()
17        }
18    }
19}

This kind of function can work well in a controlled app architecture, such as resetting to a home screen after a logout. The important part is understanding that modal dismissal and navigation popping are separate operations that happen to be wrapped together.

Prefer Flow-Specific APIs When Possible

A generic "dismiss everything" helper is tempting, but it can hide too much. In many apps, a more explicit function such as returnToLoginScreen() or finishCheckoutFlow() is safer because it describes the intended destination, not just the mechanics.

That matters even more in multi-scene apps. UIKit snippets from older codebases often assume a single global window, but modern apps can have multiple scenes. Using view.window?.rootViewController from the active controller is usually safer than trying to guess a global root from application-wide state.

If the end goal is a specific app state, it is often better to route to that state directly instead of hoping a blanket dismissal call produces the right screen in every context.

Common Pitfalls

The biggest mistake is treating pushed view controllers and modally presented view controllers as if the same API managed both. dismiss affects presentation chains, while pop affects navigation stacks.

Another issue is calling dismiss(animated:) on the topmost controller and assuming every screen in the app will disappear. UIKit only dismisses the relevant presentation chain from the right presenter.

Developers also sometimes write a "global" helper that depends on old single-window assumptions. In scene-based apps, that can target the wrong root controller.

Finally, if the action is really a business flow reset such as logout, prefer an explicit reset path over a generic close-everything utility. It is easier to maintain and test.

Summary

  • Dismissing all open view controllers usually means dismissing the modal presentation chain from the root presenter.
  • Pushed controllers are different and must be popped from a navigation controller.
  • A combined helper can work, but only if your app structure is predictable.
  • 'view.window?.rootViewController is usually safer than older global-window assumptions.'
  • When the target app state matters, flow-specific reset helpers are often better than a generic dismissal function.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.