iOS
viewWillDisappear
view controller
navigation
UIKit

viewWillDisappear Determine whether view controller is being popped or is showing a sub-view controller

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

viewWillDisappear is called in several different navigation scenarios, so by itself it does not tell you why the screen is going away. The useful distinction is whether the controller is actually being removed from its parent, being dismissed modally, or simply being covered because another controller was pushed or presented.

Start With UIKit's Built-In Flags

Inside viewWillDisappear, the two most important checks are:

  • 'isMovingFromParent'
  • 'isBeingDismissed'

Example:

swift
1import UIKit
2
3class DetailViewController: UIViewController {
4    override func viewWillDisappear(_ animated: Bool) {
5        super.viewWillDisappear(animated)
6
7        if isMovingFromParent {
8            print("This controller is being popped from a navigation stack.")
9        } else if isBeingDismissed {
10            print("This controller is being dismissed modally.")
11        } else {
12            print("Another controller is being shown on top.")
13        }
14    }
15}

This covers the most common cases.

What Happens on a Push

If a navigation controller pushes another view controller on top of the current one, the current controller's viewWillDisappear runs, but the current controller is not being popped. It is still in the navigation stack underneath the new screen.

In that case:

  • 'isMovingFromParent is false'
  • 'isBeingDismissed is usually false'

That is why the final else branch above is useful. It usually means "I am disappearing, but I still exist."

What Happens on a Pop

If the back button is tapped or the controller is popped programmatically:

swift
navigationController?.popViewController(animated: true)

then viewWillDisappear still runs, but now isMovingFromParent becomes true. That is the clean signal that this controller is leaving the parent navigation stack.

This is often the right place to detect "user is leaving this screen permanently" for cleanup that should happen only on pop.

If the controller was presented modally and is being dismissed:

swift
dismiss(animated: true)

then isBeingDismissed becomes true.

If the controller is inside a navigation controller that itself is dismissed modally, you may also need to consider the container. In more complex hierarchies, the disappearance reason can come from the parent being dismissed rather than the child acting alone.

A Practical Pattern

Here is a fuller version that distinguishes the main navigation outcomes:

swift
1override func viewWillDisappear(_ animated: Bool) {
2    super.viewWillDisappear(animated)
3
4    if isMovingFromParent {
5        print("Popped from navigation stack")
6    } else if isBeingDismissed {
7        print("Dismissed modally")
8    } else if navigationController?.topViewController !== self {
9        print("Another controller was pushed on top")
10    } else {
11        print("Disappearing for some other transition")
12    }
13}

The topViewController check is not always required, but it can help clarify push behavior while debugging a navigation flow.

Common Pitfalls

The most common mistake is assuming viewWillDisappear means the controller is being popped. It does not. Pushing another controller also triggers it.

Another issue is ignoring modal dismissal. If the controller can be presented modally, isMovingFromParent alone is not enough.

A third pitfall is doing destructive cleanup in every viewWillDisappear call. If the user is only moving to a child screen and may come back immediately, that cleanup can be premature.

Finally, complex container setups such as tab bars, split views, or embedded navigation controllers can make transitions less obvious. In those cases, inspect both the controller and its parent container state.

Summary

  • 'viewWillDisappear does not by itself explain why a controller is disappearing.'
  • Use isMovingFromParent to detect a pop from the navigation stack.
  • Use isBeingDismissed to detect modal dismissal.
  • If both are false, the controller is often just being covered by another screen.
  • Keep cleanup logic aligned with the actual navigation reason, not just the lifecycle callback.

Course illustration
Course illustration

All Rights Reserved.