iOS 13
detecting sheet
iOS development
iOS dismissed events
mobile app development

Detecting sheet was dismissed on iOS 13

Master System Design with Codemia

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

Introduction

On iOS 13, modal presentations changed because many view controllers are shown as sheets by default instead of full-screen. That means users can dismiss them with a swipe, and code that relied only on button taps or viewDidDisappear often stopped being precise enough. The correct way to detect sheet dismissal is usually through UIAdaptivePresentationControllerDelegate.

Why iOS 13 sheets behave differently

Before iOS 13, many apps presented modals full-screen and controlled dismissal more tightly. With sheet-style presentation, the system can dismiss the modal interactively. That creates a new question: how do you know the sheet was actually dismissed, not just partially dragged or requested for dismissal.

Apple added delegate callbacks on the presentation controller for exactly this reason.

Set the presentation controller delegate

The first step is assigning a delegate to the presented view controller's presentationController.

swift
1import UIKit
2
3final class EditProfileViewController: UIViewController, UIAdaptivePresentationControllerDelegate {
4    override func viewDidLoad() {
5        super.viewDidLoad()
6        presentationController?.delegate = self
7    }
8
9    func presentationControllerDidDismiss(_ presentationController: UIPresentationController) {
10        print("Sheet was dismissed")
11    }
12}

presentationControllerDidDismiss is the key callback when the dismissal has actually completed. That is usually the method you want if the goal is "run logic after the sheet is gone."

Other useful dismissal callbacks

Depending on the behavior you need, other delegate methods matter too.

swift
1func presentationControllerWillDismiss(_ presentationController: UIPresentationController) {
2    print("Sheet is about to dismiss")
3}
4
5func presentationControllerShouldDismiss(_ presentationController: UIPresentationController) -> Bool {
6    return true
7}
8
9func presentationControllerDidAttemptToDismiss(_ presentationController: UIPresentationController) {
10    print("User tried to dismiss, but dismissal was blocked")
11}

These callbacks let you distinguish between:

  • An attempted dismissal
  • A permitted dismissal
  • A completed dismissal

That is much more precise than trying to infer user intent from general lifecycle methods.

Prevent dismissal when needed

If the sheet contains unsaved data, you may want to block swipe dismissal temporarily.

swift
1override func viewDidLoad() {
2    super.viewDidLoad()
3    isModalInPresentation = true
4    presentationController?.delegate = self
5}
6
7func presentationControllerDidAttemptToDismiss(_ presentationController: UIPresentationController) {
8    print("Ask user whether to discard changes")
9}

isModalInPresentation = true tells the system not to dismiss the sheet interactively. Then presentationControllerDidAttemptToDismiss becomes useful for showing a confirmation dialog.

Why viewDidDisappear is not enough

Developers sometimes use viewDidDisappear to detect sheet dismissal. That can work in some cases, but it is broader than sheet dismissal and can fire for other reasons, such as view hierarchy changes or navigation transitions.

If your question is specifically about iOS 13 sheet dismissal, the presentation-controller delegate is more accurate and easier to reason about.

Common Pitfalls

The most common mistake is forgetting to set presentationController?.delegate. If the delegate is never assigned, the callbacks never fire.

Another issue is expecting these methods to behave the same for every modal style. If the controller is presented full-screen instead of as a sheet, the interaction model is different.

Developers also overuse viewDidDisappear for dismissal detection when they actually need sheet-specific intent and timing.

Finally, be careful about where you assign the delegate. It should be set on the presented controller's presentation controller early enough that the dismissal callbacks are available when the user interacts with the sheet.

If your sheet is embedded inside a navigation controller, double-check which controller actually owns the presentation controller. The delegate must be attached to the presented container that the system is dismissing.

Summary

  • On iOS 13, sheet-style modals should usually be observed through UIAdaptivePresentationControllerDelegate.
  • Use presentationControllerDidDismiss to detect completed dismissal.
  • Use presentationControllerWillDismiss, ShouldDismiss, and DidAttemptToDismiss for finer control.
  • Set isModalInPresentation when you need to block interactive dismissal.
  • Prefer presentation-controller callbacks over generic lifecycle methods for sheet-specific logic.

Course illustration
Course illustration

All Rights Reserved.