How to disable back swipe gesture in UINavigationController on iOS 7
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.
Introduction
The interactive back swipe gesture in UINavigationController is controlled by the interactivePopGestureRecognizer property. To disable it for a specific screen, set interactivePopGestureRecognizer?.isEnabled = false in viewWillAppear(_:) and restore it to true in viewWillDisappear(_:). This approach scopes the change to exactly one view controller and prevents the gesture policy from leaking to other screens in the navigation stack.
The Basic Approach: Per-Screen Toggle
The most common and cleanest pattern is to disable the gesture when a specific view controller appears and re-enable it when that view controller disappears.
Swift
Objective-C
Why viewWillAppear, Not viewDidLoad
Using viewDidLoad is wrong for two reasons. First, viewDidLoad runs once when the view controller is first loaded, but the gesture state needs to be set every time the screen becomes visible (including when the user navigates back to it). Second, viewDidLoad has no corresponding "undo" lifecycle method, so there is no natural place to restore the gesture.
| Lifecycle Method | Runs When | Paired With |
viewDidLoad | View is loaded into memory (once) | None |
viewWillAppear | View is about to become visible | viewWillDisappear |
viewDidAppear | View became visible | viewDidDisappear |
viewWillAppear/viewWillDisappear is the right pair because the gesture policy is tied to visibility, not to object lifetime.
Using a Gesture Recognizer Delegate
For more nuanced control, such as allowing the swipe only when certain conditions are met, implement UIGestureRecognizerDelegate:
This approach lets you conditionally block the gesture. The user can swipe back when the form is clean, but the gesture is blocked when there are unsaved changes. This is better UX than a blanket disable because it only restricts navigation when there is a real reason.
Restoring the Delegate
Setting the delegate to nil in viewWillDisappear is critical. If you forget, the navigation controller keeps a reference to your delegate, and when another view controller becomes active, the delegate methods still route to your object. This causes unexpected behavior and potential crashes if your view controller has been deallocated.
Subclassing UINavigationController for Global Control
If multiple screens in your app need to disable the back swipe, toggling the recognizer in every view controller becomes tedious. A custom navigation controller can centralize this logic:
Now any view controller that needs to disable the swipe just declares conformance:
This pattern scales well and keeps gesture policy declarations close to the view controllers that need them, without scattering lifecycle code.
SwiftUI Integration
In SwiftUI, the navigation controller's gesture recognizer is not directly exposed. To disable the back swipe in a SwiftUI view hierarchy that uses UINavigationController under the hood, you need to reach into UIKit:
This is a workaround rather than an official API. In a pure SwiftUI NavigationStack, Apple does not provide a public API to disable the back swipe as of iOS 17. The UIKit interop approach is the most reliable solution.
Handling Edge Cases
The Frozen Navigation Bug
If the user begins a back-swipe gesture but cancels it (lifts their finger before completing the swipe) on a screen where the back button is hidden, the navigation controller can enter a frozen state. The root cause is that interactivePopGestureRecognizer is still active even when the back button is not visible.
To prevent this, disable the recognizer whenever you hide the back button:
Custom Transitions
If your navigation controller uses custom transition animations, the interactive pop gesture can conflict with the transition. In these cases, either disable the gesture entirely or implement UIViewControllerInteractiveTransitioning to provide a custom interactive transition that works with your animation.
Valid Reasons to Disable the Back Swipe
Before disabling this gesture, consider whether it is truly necessary. The back swipe is a core iOS navigation pattern that users expect. Removing it without good reason makes the app feel broken.
| Reason | Alternative to Consider |
| Preventing loss of unsaved form data | Show a confirmation alert instead |
| Multi-step wizard flow | Allow back but show "discard changes?" prompt |
| Signature or drawing canvas | Disable only during active drawing |
| Full-screen media player | Use a modal presentation instead of push |
| Payment processing in progress | Disable during the network request only |
In many cases, a confirmation dialog is better UX than fully disabling navigation. The user keeps their sense of control, and accidental data loss is still prevented.
Common Pitfalls
Disabling the gesture in viewDidLoad without a corresponding restore is the most common bug. It affects every view controller pushed after yours, and the symptom (broken back swipe on unrelated screens) makes the cause hard to trace.
Setting the gesture recognizer delegate without restoring it in viewWillDisappear creates dangling references. When the navigation controller tries to call delegate methods on a deallocated object, the app crashes.
Disabling the back swipe without providing any alternative escape path (no back button, no cancel button, no close gesture) traps the user on the screen. Always provide an obvious way to navigate away.
Hiding the back button but leaving interactivePopGestureRecognizer enabled causes the frozen navigation bug described above. Always pair hidesBackButton = true with gesture disable.
Testing only the happy path (pushing and popping cleanly) misses the case where the user starts a swipe, cancels it, then tries to navigate again. Test partial swipe cancellation on every screen where you modify the gesture recognizer behavior.
Summary
- Disable the back swipe by setting
interactivePopGestureRecognizer?.isEnabled = falseinviewWillAppear. - Always restore it to
trueinviewWillDisappearto prevent leaking the policy to other screens. - Use a
UIGestureRecognizerDelegatefor conditional control (e.g., only block when there are unsaved changes). - Centralize gesture policies in a custom
UINavigationControllersubclass when many screens need different rules. - Always provide an alternative navigation path (back button, cancel, close) when disabling the swipe gesture.
- Test partial swipe cancellation to catch the frozen navigation bug.
Related reading
- How to disable Crashlytics during development
- How to disable horizontal scrolling of UIScrollView?
- How to disable night mode in my application even if night mode is enable in android 9.0 pie?
- How to disable RecyclerView scrolling?
- how to disable rotation in React Native?
- How to disable scrolling in UITableView table when the content fits on the screen
- How to disable the highlight control state of a UIButton?
- How to disable UITextField editing but still accept touch?
.png&w=3840&q=75)
Tackling System Design Interview Problems
A short course that equips you with the skills to approach system design interviews methodically.
Start the free courseTrack 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.