Swift
SwiftUI state management
SwiftUI rebuilds views from state. The trick is choosing the right property wrapper so ownership and updates flow the way you expect.
The core property wrappers
| Wrapper | Owns the data? | Use for |
|---|---|---|
| @State | Yes | simple value-type state local to one view |
| @Binding | No | a two-way reference to state owned elsewhere |
| @Observable / @StateObject | Yes | reference-type model owned by the view |
| @ObservedObject | No | a model passed in from a parent |
| @EnvironmentObject | No | shared model injected into the hierarchy |
@State and @Binding
@State is private to a view. Pass a two-way handle to a child with @Binding using the $ prefix.
struct CounterView: View {
@State private var count = 0
var body: some View {
Stepper('Count: \(count)', value: $count)
ChildView(count: $count)
}
}
struct ChildView: View {
@Binding var count: Int
var body: some View {
Button('Reset') { count = 0 }
}
}
Observable models
For anything beyond a couple of values, use an observable reference type. The view that creates it uses @StateObject (or the newer @Observable macro), children receive it as @ObservedObject.
final class CartModel: ObservableObject {
@Published var items: [Item] = []
}
struct CartView: View {
@StateObject private var cart = CartModel()
var body: some View { /* ... */ EmptyView() }
}
