Navigation & Passing Data
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.
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
UINavigationControllerto 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. Usepresent/dismissfor modal screens.