iOS
Objective-C
development
deprecated
dismissModalViewControllerAnimated

dismissModalViewControllerAnimated deprecated

Master System Design with Codemia

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

Introduction

dismissModalViewControllerAnimated: was part of the older UIKit modal presentation API. Apple deprecated it in favor of dismissViewControllerAnimated:completion:, which fits the modern view controller presentation model and supports completion callbacks.

If you still see the deprecated call in legacy Objective-C code, the fix is straightforward. The important part is understanding which controller should dismiss the presentation and when the completion block runs.

What Replaced the Deprecated API

Older iOS code often looked like this:

objective-c
[self dismissModalViewControllerAnimated:YES];

The modern replacement is:

objective-c
[self dismissViewControllerAnimated:YES completion:nil];

The newer method works for modal presentations created with presentViewController:animated:completion: and gives you a completion block for cleanup, state updates, or chained navigation.

Here is a basic presentation and dismissal flow in Objective-C:

objective-c
1- (void)showDetails {
2    DetailsViewController *details = [[DetailsViewController alloc] init];
3    [self presentViewController:details animated:YES completion:nil];
4}
5
6- (void)closeDetails {
7    [self dismissViewControllerAnimated:YES completion:^{
8        NSLog(@"Details controller dismissed");
9    }];
10}

That is the direct replacement most projects need.

Who Should Call Dismiss

In UIKit, the presenting controller manages the modal relationship, but the presented controller can still ask UIKit to dismiss itself. In practice, both of the following are common and valid:

  • The presented controller calls [self dismissViewControllerAnimated:YES completion:nil];
  • The presenting controller calls [self.presentedViewController dismissViewControllerAnimated:YES completion:nil];

The first option is often simpler inside a modal screen's cancel or done action:

objective-c
- (IBAction)doneButtonTapped:(id)sender {
    [self dismissViewControllerAnimated:YES completion:nil];
}

If your modal is embedded in a navigation controller, dismiss the modal container rather than trying to pop it off the navigation stack. Modal dismissal and navigation popping are different operations.

Why Apple Deprecated the Old Method

The deprecation reflects a broader UIKit cleanup. Apple moved from a specialized modal API toward a more consistent view controller presentation system. The newer methods:

  • match presentViewController:animated:completion:
  • support completion blocks
  • work better with custom transitions
  • fit newer presentation styles such as form sheets and page sheets

That consistency matters when an app grows beyond a single full-screen modal flow.

Legacy projects often mix modal presentation with navigation-controller pushes, which is where confusion starts. A modal controller should be dismissed. A pushed controller should be popped.

objective-c
1// Modal dismissal
2[self dismissViewControllerAnimated:YES completion:nil];
3
4// Navigation stack pop
5[self.navigationController popViewControllerAnimated:YES];

If you use the wrong operation, UIKit may do nothing or remove the wrong screen. Before changing old code, verify whether the screen was shown with presentViewController or pushed with pushViewController.

Migrating Legacy Code Safely

For most projects, migration is a text-level API update plus a quick check of the call site. Replace the deprecated call, then verify that the controller being dismissed is actually the one presented modally.

A common legacy pattern looks like this:

objective-c
- (void)cancel:(id)sender {
    [self dismissModalViewControllerAnimated:YES];
}

After migration:

objective-c
- (void)cancel:(id)sender {
    [self dismissViewControllerAnimated:YES completion:nil];
}

If cleanup logic depends on the dismissal finishing, move that logic into the completion block:

objective-c
1- (void)cancel:(id)sender {
2    [self dismissViewControllerAnimated:YES completion:^{
3        [self.sessionManager resetDraftState];
4    }];
5}

That is more reliable than running the cleanup immediately before the animation completes.

Swift Equivalent

Many mixed iOS codebases use both Objective-C and Swift. The Swift call is nearly identical:

swift
1@IBAction func closeTapped(_ sender: UIButton) {
2    dismiss(animated: true) {
3        print("Modal dismissed")
4    }
5}

If you are modernizing an older project, it helps to remember that the API concept stayed the same even though the syntax became shorter.

Common Pitfalls

One common mistake is dismissing the wrong controller. If a modal screen contains a navigation controller, dismiss the presented navigation controller instead of trying to pop the visible child controller.

Another issue is confusing modal dismissal with stack navigation. dismissViewControllerAnimated:completion: closes a modal presentation. popViewControllerAnimated: removes a controller from a navigation stack. They solve different problems.

Developers also sometimes ignore the completion block and trigger follow-up UI too early. If the next action depends on the modal being gone, put that work in the completion handler.

Finally, do not keep deprecated calls around for backward compatibility unless you truly support very old iOS targets. For any modern project, the replacement API is the correct default.

Summary

  • 'dismissModalViewControllerAnimated: is deprecated and should be replaced.'
  • Use dismissViewControllerAnimated:completion: for modern UIKit modal dismissal.
  • The presented controller can usually dismiss itself with the new API.
  • Use the completion block for cleanup or follow-up navigation.
  • Be careful not to confuse modal dismissal with navigation controller popping.

Course illustration
Course illustration

All Rights Reserved.