State Management: @State, @Binding & the Observation Framework
iOS Development Fundamentals
Chapter 6 · State Management: @State, @Binding & the Observation Framework
Every SwiftUI view so far has been static. This chapter covers how a view actually changes in response to real user interaction — and resolves a real, genuine puzzle Chapters 4-5 deliberately left open: if a view is a cheap struct that SwiftUI recreates constantly, how does it ever "remember" anything between those recreations?
@State: A View's Own Local Data
@State is a real, genuine exception to the "struct copy is fully independent" rule from
Chapter 4. SwiftUI stores a @State property's own actual value outside the
view struct itself, in storage the framework manages and keys to that specific view's own identity in the
view tree. Every time SwiftUI recreates the CounterView struct, the new struct's own
count property is reconnected to that same real, persistent storage — the struct itself is
disposable, but the state it references survives.
private@State property private is Apple's own real, standard convention — it
belongs to this specific view alone. When a value genuinely needs to be shared with a child view, it's
passed explicitly, not exposed directly, which is exactly what @Binding covers next.
The $ Prefix & @Binding
Every SwiftUI property wrapper exposes a real projected value, accessed with a
$ prefix — for @State, that projected value is a real,
two-way connection to the underlying data, called a Binding. Passing
$count instead of count hands a child view the ability to both read and write the
parent's own state, not just a copy of its current value.
ToggleRow flipping its own real Toggle switch genuinely updates
SettingsView's own notificationsOn — this is the whole point of a real
Binding, not a bug. Passing plain notificationsOn (no $) instead of
$notificationsOn would only hand over the current value, one-way, with no way for the child to
write back — and wouldn't even compile against a @Binding parameter, since the types
genuinely differ (Bool vs. Binding<Bool>).
Shared Model Data: The Real Observation Framework
@State and @Binding are for one value, owned by one view, optionally shared down
to its own children. Real apps also need genuinely shared, reference-type model
objects — data used across several unrelated parts of the screen at once. As of iOS 17 /
Swift 5.9, Apple's real, current answer is the Observation framework, replacing
the older ObservableObject protocol and its required @Published property
wrapper.
| Tool | Real Use Case |
|---|---|
@State | A simple, value-type property owned by one view |
@Binding | A two-way connection to a value owned by a parent view |
@Observable | Marks a class as a real, shared model whose changes SwiftUI automatically tracks — replaces ObservableObject/@Published |
@Bindable | Lets a view create real two-way bindings ($profile.name) into an @Observable class's own properties |
ObservableObject approach, UserProfile's properties each needed
an explicit @Published annotation to be tracked. @Observable tracks every stored
property automatically — real, current Apple guidance, and one clear, direct example of the site's own
Claude Code Agents courses' broader theme that a fast-moving framework's tutorials can genuinely go stale;
always check which pattern a source is actually describing.
Hands-On Exercises
Build a StepperView with an @State private var value = 0, showing the current value in a Text alongside two Buttons ("+" and "-") that adjust it. Explain, in your own words, why value correctly persists across taps even though SwiftUI recreates the StepperView struct on every update.
Build a parent view with @State private var username = "", passing a Binding<String> down to a child view UsernameField that renders a real TextField bound to it. Confirm typing in the field updates the parent's own state.
Explain, in your own words, why a shared piece of data used across two unrelated parts of an app's screen is a better real fit for an @Observable class than for @State, connecting your answer to structs being value types and classes being reference types (Chapter 4).
Chapter 6 Quick Reference
@State: a view's own local value, persisted by SwiftUI outside the disposable struct itself$prefix: a property wrapper's projected value — for@State, a real, two-wayBinding@Binding: lets a child view read and write a value it doesn't itself own@Observable(iOS 17/Swift 5.9): marks a class as a real, automatically-tracked shared model, replacingObservableObject/@Published@Bindable: creates real two-way bindings into an@Observableclass's own properties from inside a view