Navigation & Multi-Screen Apps
iOS Development Fundamentals
Chapter 8 · Navigation & Multi-Screen Apps
Real apps have more than one screen. This chapter covers SwiftUI's two genuinely different ways of showing a second screen — pushing a new one onto a real navigation stack, and presenting one modally above the current screen — and how to pass real, typed data along with either.
NavigationStack & NavigationLink
NavigationStack, introduced in iOS 16, is Apple's real, current tool for
hierarchical navigation — replacing the older NavigationView. It manages a genuine stack of
screens, with a real back button and swipe-to-go-back gesture handled automatically.
NavigationLink,
NavigationLink(value:) only declares what real data was tapped —
.navigationDestination(for:destination:), attached once at the
NavigationStack's own level, decides what view to actually show for that type
of data. Any real Task, tapped from anywhere in this stack, routes through the same one
real destination.
navigationDestination(for:) matches by real, exact type, using Hashable
conformance to track navigation state — Task needs to be both Identifiable
(for List/ForEach, Chapter 7) and Hashable (for this).
Modal Presentation: .sheet()
A modal sheet is a real, genuinely different pattern from pushing a screen — it floats above the current screen rather than replacing it, and is dismissed by swiping down or an explicit action, not a back button.
A second, real form, .sheet(item:), presents a sheet whenever a bound optional value becomes
non-nil — genuinely useful when the sheet's own content depends directly on which specific
item was tapped, rather than a plain on/off flag.
| Tool | Real Behavior | Use It For |
|---|---|---|
NavigationLink | Pushes a new screen onto the stack; a real back button/swipe returns | Drilling into a hierarchy — a list to a detail screen |
.sheet() | Presents a screen modally above the current one; dismissed by the user | A focused, temporary task — adding an item, a form, a confirmation |
Passing Data Back
NavigationLink/navigationDestination naturally hands data forward,
into the destination. Sending data back — like a newly created task returning from
NewTaskView — reuses this course's own Chapter 6 tools directly: a @Binding
passed into the sheet's own view, or an @Observable model shared between both screens.
Hands-On Exercises
Build a NavigationStack containing a List of five sample Task items (using this chapter's own struct), each a NavigationLink(value:), with a .navigationDestination(for: Task.self) showing a simple detail screen with the task's own title.
Add an @State private var isShowingSheet = false and a toolbar Button to the view from Exercise 1, presenting a simple modal sheet with .sheet(isPresented:) when tapped.
Explain, in your own words, why routing every Task through one shared .navigationDestination(for: Task.self) — rather than embedding a destination view inside each individual NavigationLink — is a genuinely better real design for a list with many rows.
Chapter 8 Quick Reference
NavigationStack(iOS 16+) — the real, current hierarchical navigation container, replacingNavigationViewNavigationLink(value:)declares what data was tapped;.navigationDestination(for:destination:), attached once, decides what view to show for that type.sheet(isPresented:)/.sheet(item:)present a screen modally above the current one, dismissed by the user, not a back buttonnavigationDestination(for:)requires the routed type to beHashable- Sending data back from a pushed or presented screen reuses
@Bindingor an@Observableshared model (Chapter 6)