Swift

How to dismiss ViewController in Swift

19 September 2026 · 10 min read

How to dismiss ViewController in Swift

Navigating the intricacies of iOS development often involves managing the flow of ViewControllers within your application. One fundamental skill every Swift developer must master is understanding how to dismiss ViewController in Swift. This seemingly simple task is crucial for creating intuitive user experiences, handling navigation, and managing memory efficiently. Whether you’re dealing with modal presentations, navigation stacks, or custom transitions, knowing the proper techniques for dismissing ViewControllers ensures your app behaves predictably and avoids common pitfalls like memory leaks or unexpected UI behavior. This article will comprehensively cover various methods to dismiss ViewControllers in Swift, providing clear examples and practical tips to enhance your iOS development skills.

Understanding ViewController Presentation Styles

Before diving into the “how,” it’s crucial to understand “why” certain dismissal methods work best for specific presentation styles. ViewControllers can be presented modally, pushed onto a navigation stack, or managed within a container view. Each presentation style dictates the appropriate dismissal strategy. For instance, a ViewController presented modally is typically dismissed using the dismiss(animated:completion:) method, while a ViewController pushed onto a navigation stack is dismissed using the popViewController(animated:) method of the UINavigationController. Understanding these distinctions is fundamental to avoiding unexpected behavior in your app. Consider the user experience when choosing your presentation and dismissal methods; a smooth, intuitive transition is always the goal.

Consider a scenario where you’ve presented a settings screen modally. The user interacts with the settings, makes changes, and then expects to return to the main screen. Using the wrong dismissal method could lead to the settings screen remaining in memory or, worse, crashing the app. Similarly, if you’re using a navigation controller to manage a series of screens, popping the wrong ViewController can disrupt the user’s workflow. This is why it’s vital to understand the underlying mechanics of ViewController presentation and dismissal in Swift. This understanding will save you from countless debugging hours and allow you to build more robust and user-friendly iOS applications. Remember that managing the view controller lifecycle effectively contributes significantly to the overall performance and stability of your app.

The method you choose to dismiss a ViewController also impacts animations and transitions. Modal presentations often use custom transitions to create visually appealing effects, and the dismissal method should complement these transitions. Using the appropriate method guarantees that the reverse animation plays correctly, maintaining a consistent user experience. According to Apple’s Human Interface Guidelines, transitions should be smooth and purposeful, guiding the user through the app’s interface in a clear and intuitive manner. Ignoring these guidelines can lead to a jarring experience, potentially impacting user engagement and satisfaction. Apple’s Human Interface Guidelines provides guidance for creating intuitive user experiences.

Dismissing Modally Presented ViewControllers

Dismissing a ViewController that was presented modally is generally straightforward, but it’s important to understand the nuances. The primary method for dismissing a modal ViewController is dismiss(animated:completion:). This method is called on the ViewController that presented the modal view. For example, if ViewController A presented ViewController B modally, then ViewController A is responsible for dismissing ViewController B. The animated parameter controls whether the dismissal is animated, and the completion parameter allows you to execute code after the dismissal animation completes. This is useful for performing tasks like updating data or refreshing the UI.

A common mistake is attempting to dismiss the modal ViewController from within itself. While this can work, it’s not the recommended approach. Instead, use a delegate pattern or a closure to communicate back to the presenting ViewController. This ensures that the presenting ViewController retains control over the dismissal process and can handle any necessary cleanup or updates. For instance, you could define a protocol in the modal ViewController that has a method for dismissing the view, and then implement that protocol in the presenting ViewController. The modal ViewController can then call this method to trigger the dismissal.

Here’s how you can dismiss a modally presented ViewController using a delegate:

  1. Define a protocol in the modal ViewController:
protocol ModalViewControllerDelegate: AnyObject { func modalViewControllerDidDismiss() }
  1. Add a delegate property to the modal ViewController:
weak var delegate: ModalViewControllerDelegate?
  1. Call the delegate method when the modal view is ready to dismiss:
delegate?.modalViewControllerDidDismiss()
  1. Implement the delegate method in the presenting ViewController and dismiss the modal view.

It is important to understand that view controller dismissal is not instantaneous. The animation takes time and until the animation completes, the dismissed view controller remains in memory. By using the completion block, you ensure that your code executes only after the dismissal animation is finished, which is useful for updating the UI or releasing resources. The completion block also helps to avoid race conditions and ensures that the app’s state is consistent.

Popping ViewControllers from a Navigation Stack

When a ViewController is pushed onto a UINavigationController’s stack, dismissing it involves “popping” it off the stack. The UINavigationController provides several methods for this, each with slightly different behavior. The most common method is popViewController(animated:), which removes the top ViewController from the stack and animates the transition back to the previous ViewController. The animated parameter controls whether the transition is animated. This method returns the popped ViewController, allowing you to perform any necessary cleanup on it.

Sometimes, you might want to pop multiple ViewControllers at once. For example, if the user has navigated deep into a multi-step process and wants to return to the beginning, you can use popToRootViewController(animated:). This method pops all ViewControllers off the stack except for the root ViewController, effectively returning the user to the starting point. Alternatively, you can use popToViewController(_:animated:) to pop to a specific ViewController in the stack. This method requires a reference to the target ViewController, which can be obtained by iterating through the UINavigationController’s viewControllers array. It’s very important to ensure you have a valid reference to the target view controller, otherwise the app can crash.

Here are some key differences between the pop methods:

  • popViewController(animated:): Pops only the top ViewController.
  • popToRootViewController(animated:): Pops all ViewControllers except the root.
  • popToViewController(_:animated:): Pops to a specific ViewController in the stack.

Dismissing view controllers from a navigation stack allows for a clear and intuitive user experience by providing a natural flow through the app. By using the correct method, you ensure that the navigation stack remains consistent and that the user can easily navigate back to previous screens. Moreover, proper navigation management improves app performance by releasing resources associated with dismissed view controllers. Therefore, mastering the techniques for popping view controllers is essential for any iOS developer.

Using Unwind Segues for Complex Navigation

Unwind segues offer a powerful and flexible way to dismiss ViewControllers, especially in complex navigation scenarios where you need to return to a specific ViewController from multiple points in your app. An unwind segue defines a path back through the navigation hierarchy, allowing you to navigate back to a specific view controller, potentially skipping intermediate steps. This is particularly useful when you have a complex flow and need a simple way to return to a previous state.

To implement an unwind segue, you first need to define an @IBAction method in the ViewController you want to unwind to. This method takes a UIStoryboardSegue as a parameter. The segue object provides information about the source ViewController and the identifier of the segue. Then, in Interface Builder, you can connect the button or gesture that triggers the unwind segue to the exit icon of the source ViewController, selecting the unwind action you defined in the destination ViewController. This creates a visual connection that defines the unwind path.

For example, suppose you have three ViewControllers: A, B, and C, where A is the root, B is pushed onto A, and C is pushed onto B. If you want to unwind from C directly to A, you would define an unwind action in A and then connect the exit icon in C to that action. When the user triggers the unwind segue from C, the navigation controller will automatically pop B and C, returning to A. According to a study by Nielsen Norman Group, clear and predictable navigation is crucial for user satisfaction. Nielsen Norman Group - Navigation Design Examples provides guidance for clear and predictable navigation. Unwind segues help achieve this by providing a consistent and intuitive way to return to previous states.

Infographic here
Here are some advantages of using unwind segues:
  • Centralized navigation logic: The unwind action is defined in the destination ViewController, making it easy to manage navigation paths.
  • Visual representation: The connections in Interface Builder provide a clear visual representation of the navigation flow.
  • Flexibility: Unwind segues can be triggered from multiple points in the app, allowing you to easily return to a specific state from different contexts.

Best Practices for Dismissing ViewControllers

Adhering to best practices when dismissing ViewControllers can significantly improve your app’s stability, performance, and user experience. One crucial aspect is managing memory efficiently. Always ensure that you release any resources held by the dismissed ViewController, such as timers, network connections, or large data structures. Failing to do so can lead to memory leaks, which can degrade performance and eventually cause your app to crash. Use the deinit method to deallocate resources when the ViewController is deallocated.

Another important consideration is handling asynchronous operations. If the ViewController is performing any asynchronous tasks, such as network requests, ensure that you cancel them before dismissing the view. Otherwise, the completion handlers for these tasks might try to update the UI after the ViewController has been deallocated, leading to crashes. You can use URLSession.shared.invalidateAndCancel() to cancel any ongoing URLSession tasks. Also make sure to invalidate timers or remove observers to avoid unexpected behavior.

It’s also important to be mindful of the context in which you’re dismissing the ViewController. If the dismissal is triggered by a user action, provide clear feedback to the user, such as an animation or a progress indicator. This helps the user understand what’s happening and prevents confusion. If the dismissal is triggered programmatically, ensure that it doesn’t disrupt the user’s workflow. For instance, avoid dismissing a ViewController unexpectedly in the middle of a user interaction. For more on best practices for iOS development, see Ray Wenderlich tutorials.

To summarize, here are some crucial practices when dismissing view controllers in Swift:

  • Release resources to prevent memory leaks.
  • Cancel asynchronous operations to avoid crashes.
  • Provide user feedback for dismissals triggered by user actions.

Featured Snippet: Dismissing a ViewController presented modally in Swift is done using the dismiss(animated:completion:) method. This method should be called on the ViewController that presented the modal view. The animated parameter controls whether the dismissal is animated, and the completion parameter allows you to execute code after the dismissal animation completes. This ensures a smooth transition and allows for any necessary cleanup or updates.

FAQ: Dismissing ViewControllers in Swift

Q: What's the difference between `dismiss(animated:completion:)` and `popViewController(animated:)`?
A: `dismiss(animated:completion:)` is used to dismiss a ViewController that was presented modally, while `popViewController(animated:)` is used to remove a ViewController from a UINavigationController's stack.
Q: How can I dismiss a ViewController from within itself?
A: It's generally recommended to use a delegate pattern or a closure to communicate back to the presenting ViewController, which can then call `dismiss(animated:completion:)`.
Q: What are unwind segues, and when should I use them?
A: Unwind segues provide a way to navigate back through the navigation hierarchy, allowing you to return to a specific ViewController from multiple points in your app. They are useful in complex navigation scenarios.
Q: How can I prevent memory leaks when dismissing ViewControllers?
A: Always release any resources held by the dismissed ViewController, such as timers, network connections, or large data structures, in the `deinit` method.
Q: What should I do about asynchronous operations when dismissing ViewControllers?
A: Cancel any asynchronous tasks before dismissing the ViewController to prevent crashes caused by completion handlers trying to update a deallocated UI.
Mastering the art of dismissing ViewControllers in Swift is a cornerstone of effective iOS development. We've explored various methods, from the simplicity of `dismiss(animated:completion:)` for modal presentations to the strategic use of unwind segues for complex navigation flows. Remember to prioritize memory management, handle asynchronous operations gracefully, and always consider the user experience when choosing your dismissal strategy. Implementing these techniques will empower you to create robust, efficient, and user **Question & Answer :**

I am trying to dismiss a ViewController in swift by calling dismissViewController in an IBAction

@IBAction func cancel(sender: AnyObject) { self.dismissViewControllerAnimated(false, completion: nil) println("cancel") } @IBAction func done(sender: AnyObject) { self.dismissViewControllerAnimated(false, completion: nil) println("done") } 

random image of a segue

I could see the println message in console output but ViewController never gets dismissed. What could be the problem?

From you image it seems like you presented the ViewController using push

The dismissViewControllerAnimated is used to close ViewControllers that presented using modal

Swift 2

navigationController.popViewControllerAnimated(true) 

Swift 4

navigationController?.popViewController(animated: true) dismiss(animated: true, completion: nil)