← All courses

Navigation & Passing Data

🗓 May 31, 2026 ⏱ 2 min read

How iOS navigation works

Most iOS apps use a UINavigationController, which manages a stack of screens. Pushing a screen slides it in from the right (with an automatic back button); popping it slides back. Think of it like a stack of cards — you push to go deeper and pop to go back.

List Detail Edit

Pushing a screen in code

let detailVC = ProfileViewController()
detailVC.userId = 42                 // pass data forward (next section)
navigationController?.pushViewController(detailVC, animated: true)

// go back programmatically
navigationController?.popViewController(animated: true)

Passing data forward

The simplest way to send data to the next screen is to set a property on it before pushing — exactly as detailVC.userId = 42 above. The detail screen then reads userId in its viewDidLoad.

Passing data back (delegation or closures)

To send data back from a screen (e.g. the edit screen returns the new name), use a delegate or a closure callback:

class EditViewController: UIViewController {
    var onSave: ((String) -> Void)?      // closure callback

    func save(_ newName: String) {
        onSave?(newName)                 // tell the previous screen
        navigationController?.popViewController(animated: true)
    }
}

// when pushing it:
let edit = EditViewController()
edit.onSave = { [weak self] newName in
    self?.nameLabel.text = newName
}

Presenting modally

Some screens (a login sheet, a compose form) appear over the current screen rather than pushing. Use present for those:

let sheet = ComposeViewController()
present(sheet, animated: true)
// dismiss from inside the sheet:
dismiss(animated: true)

Storyboards and segues

If you use Storyboards, navigation can be wired visually with segues, and you pass data in prepare(for:sender:). Code-based navigation (shown above) is increasingly preferred for clarity and testability.

Common mistakes

  • Forgetting that a screen needs to be inside a UINavigationController to push.
  • Creating retain cycles in callback closures — use [weak self].
  • Trying to push when you should present (and vice versa).
Summary: A navigation controller manages a stack of screens (push/pop). Pass data forward by setting properties before pushing, and back via delegates or closures. Use present/dismiss for modal screens.