Dismissing a Modal View Controller That Just Won't Cooperate: A UIKit Conundrum

Dismiss Modal View Controller Not Working

=====================================================

As a developer, we’ve all been there - trying to dismiss a modal view controller that’s not cooperating. In this article, we’ll dive into the world of UIKit and explore why our code isn’t working as expected.

Understanding the Problem


We have a UITabBarController with a UINavigationController, which presents an MVC (Model-View-Controller) view controller. This MVC has a nib with a view and a UINavigationController. The navigation controller’s view is added as a subview to the MVC’s view. We want to dismiss the MVC when either of two buttons are pressed.

The Code


We’ve tried various approaches, but nothing seems to work:

[self dismissModalViewControllerAnimated:YES];
[self.parentViewController dismissModalViewControllerAnimated:YES];
[self.navigationController dismissModalViewControllerAnimated:YES];
[self.parentViewController.navigationController dismissModalViewControllerAnimated:YES];

// or

function in parentView {
  self.parentViewController.myFunction();
}

// or

[self.parentViewController myFunction()];

As we can see, the issue seems to be with the modal view controller’s relationship with its parent view controller.

The Solution


So, what’s going on here? Let’s take a closer look at how UIKit handles modal view controllers.

When a view controller presents another one using presentModalViewController:, it becomes a parent view controller. This means that the presented view controller is now a child of the presenting view controller.

The problem with our code is that we’re trying to dismiss the modal view controller from its own parent, rather than from itself. In other words, when we call [self.parentViewController dismissModalViewControllerAnimated:YES];, we’re essentially telling the parent view controller to dismiss something that’s already being dismissed.

Choice #1: Dismissing from Parent View Controller


So, what can we do instead? Let’s try dismissing the modal view controller from its own parent. We can do this by calling [self.parentViewController dismissModalViewControllerAnimated:YES]; on the presented view controller itself.

[self dismissModalViewControllerAnimated:YES];

By doing so, we’re essentially telling our parent view controller to dismiss something that it already knows about and has control over.

Choice #2: Removing Navigation Controller


But wait - what if we don’t need a navigation controller at all? We can simply add a UINavigationBar to our MVC and place the buttons on it. Then, we can add actions to them and call [self.parentViewController dismissModalViewControllerAnimated:YES];.

// Add UINavigationBar to MVC
[self.view addSubview:[self.navigationController navigationController]];

// Place buttons on navigation bar
UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(cancel)];
[self.navigation controller setNavigationBarItem cancelButton];

// Add action to cancel button
- (void)cancel {
  [self.parentViewController dismissModalViewControllerAnimated:YES];
}

By doing so, we’re removing the navigation controller from the picture altogether.

Conclusion


So, why didn’t our code work as expected? It’s because we were trying to dismiss a modal view controller from its own parent, rather than from itself. By understanding how UIKit handles modal view controllers and choosing between two different approaches, we can successfully dismiss those pesky modals.

Remember, the next time you’re stuck with a dismissing modal view controller that just won’t cooperate - take a step back, think about your code, and try one of these solutions!


Last modified on 2025-04-14