How to check if a view controller is presented modally or pushed on a navigation stack?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
In UIKit, the same view controller class can appear in different ways: pushed onto a navigation stack, presented modally, embedded inside a navigation controller that was presented modally, or hosted inside a tab bar controller. That is why checking how a screen arrived is slightly more subtle than one single property lookup.
The practical answer is to inspect the surrounding controller relationships and choose the rule that matches your UI architecture. There is no single universal boolean built into UIKit for "modal versus pushed."
The Simplest Modal Check
If a view controller was directly presented, presentingViewController is often enough:
That works for many simple cases, but it is incomplete. A pushed view controller inside a navigation controller that itself was presented modally can still have different relationship values than a directly presented controller.
A More Robust Helper
A common UIKit helper looks like this:
Usage:
This handles the most common modal-container cases better than a single property check.
Detect Whether It Was Pushed
If the controller is inside a navigation controller and is not the root, it was pushed:
Or more explicitly:
However, the exact meaning of "pushed" becomes tricky if the whole navigation controller itself was presented modally. In that case, the screen is pushed inside a modal flow.
Why Context Matters
Suppose this happens:
- present a
UINavigationControllermodally - push several screens inside it
Those inner screens are both:
- part of a navigation stack
- inside a modal presentation flow
So you need to decide which question you are asking:
- was this exact controller pushed inside its navigation controller?
- is this screen currently participating in a modal flow overall?
UIKit can support both answers, but your back-button logic must choose one definition.
Use the Check for Dismissal Logic Carefully
A common use case is deciding whether a close button should dismiss or pop:
This is fine as long as your app's navigation patterns are consistent. If you mix modal flows, tabs, split views, and deep navigation stacks, centralizing the logic in one helper is usually safer than repeating ad hoc checks throughout the app.
Common Pitfalls
- Assuming
presentingViewController != nilcovers every modal-related case. - Forgetting that a navigation controller can be presented modally while its child screens are pushed.
- Using one simplistic rule in an app with mixed tabs, modals, and embedded navigation controllers.
- Treating "pushed" and "part of a modal flow" as if they were the same question.
- Scattering presentation checks around the codebase instead of centralizing them in one helper.
Summary
- UIKit does not provide one perfect built-in flag for modal versus pushed.
- '
presentingViewControlleris a useful start but not the whole story.' - A helper that checks navigation and tab bar container relationships is more reliable.
- Decide whether you care about direct presentation style or overall flow context.
- Centralize the rule if the app uses several different navigation patterns.

