Swift
iOS Development
View Controller
Navigation
Programming Tutorial

How to Navigate from one View Controller to another using Swift

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

Navigating from one view controller to another in iOS depends on the kind of transition you want. The two most common choices are pushing onto a navigation stack and presenting modally. The right answer is less about syntax and more about choosing the correct container and presentation style for the screen flow.

Push Navigation with UINavigationController

Use push navigation when the next screen is part of a drill-down flow such as list to detail. This requires the current view controller to be inside a UINavigationController.

swift
1import UIKit
2
3final class FirstViewController: UIViewController {
4    @IBAction func showDetails(_ sender: UIButton) {
5        let second = SecondViewController()
6        navigationController?.pushViewController(second, animated: true)
7    }
8}
9
10final class SecondViewController: UIViewController {
11}

The navigation controller manages the back button automatically. If navigationController is nil, the push will do nothing, which is a sign that the current controller is not embedded in a navigation stack.

Present a View Controller Modally

Use modal presentation when the new screen interrupts the current flow or behaves like a self-contained task such as login, settings, or compose.

swift
1import UIKit
2
3final class FirstViewController: UIViewController {
4    @IBAction func openSettings(_ sender: UIButton) {
5        let settings = SettingsViewController()
6        settings.modalPresentationStyle = .fullScreen
7        present(settings, animated: true)
8    }
9}
10
11final class SettingsViewController: UIViewController {
12    @IBAction func close(_ sender: UIButton) {
13        dismiss(animated: true)
14    }
15}

This does not depend on a navigation controller. The presented view controller is responsible for dismissing itself or being dismissed by the presenting controller.

Instantiate from a Storyboard

If the view controllers live in a storyboard, instantiate them by storyboard identifier instead of calling the class initializer directly.

swift
1import UIKit
2
3final class FirstViewController: UIViewController {
4    @IBAction func showProfile(_ sender: UIButton) {
5        let storyboard = UIStoryboard(name: "Main", bundle: nil)
6        guard let profile = storyboard.instantiateViewController(
7            withIdentifier: "ProfileViewController"
8        ) as? ProfileViewController else {
9            return
10        }
11
12        navigationController?.pushViewController(profile, animated: true)
13    }
14}

This is the correct approach when the layout is defined in Interface Builder.

Use Segues When the Flow Is Declared in the Storyboard

Storyboards also support segues. A segue is a transition defined visually between scenes.

You can trigger one in code:

swift
1override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
2    if let destination = segue.destination as? DetailViewController {
3        destination.titleText = "Passed from FirstViewController"
4    }
5}
6
7@IBAction func goToDetail(_ sender: UIButton) {
8    performSegue(withIdentifier: "ShowDetail", sender: self)
9}

Segues are convenient when the navigation flow is simple and storyboard-driven. Programmatic navigation is often clearer once the project grows and flows become dynamic.

Pass Data During Navigation

Navigation is often coupled with data transfer. For programmatic pushes, assign properties before presenting the destination.

swift
1final class ProductViewController: UIViewController {
2    var productName: String = ""
3}
4
5final class CatalogViewController: UIViewController {
6    func openProduct() {
7        let productVC = ProductViewController()
8        productVC.productName = "Keyboard"
9        navigationController?.pushViewController(productVC, animated: true)
10    }
11}

For storyboard segues, use prepare(for:sender:) as shown earlier.

Choose the Navigation Pattern Intentionally

A useful rule is:

  • push when the user is moving deeper into a hierarchical flow
  • present when the user is entering a temporary or separate task

That choice affects back behavior, screen ownership, and how the app feels. A technically correct transition can still be a bad UX choice if the navigation pattern is wrong.

In larger UIKit apps, coordinators or routers are often used to centralize navigation instead of having each view controller create the next one directly. That is not required for simple apps, but it becomes valuable when:

  • the same screen can be reached from multiple places
  • navigation depends on app state
  • you want view controllers to stay focused on UI logic

Even if you are not using a coordinator pattern yet, it helps to avoid burying complex routing rules inside random button handlers.

Common Pitfalls

The most common mistake is trying to push a view controller when the current controller is not embedded in a UINavigationController. Another is creating a storyboard-based view controller with SecondViewController() instead of instantiating it from the storyboard, which skips the designed scene. Developers also often use modal presentation for flows that should really be push navigation, which makes back behavior feel awkward. A final issue is forgetting to pass required data before the transition, leaving the destination screen without the state it needs.

Summary

  • Use pushViewController for drill-down navigation inside a navigation controller.
  • Use present for modal flows such as login or settings.
  • Instantiate storyboard-based controllers from the storyboard, not with plain initializers.
  • Use prepare(for:sender:) or direct property assignment to pass data.
  • Choose the navigation style based on the user flow, not just on what code is shortest.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.