Instruction
State & Observable
In a SwiftUI app, every data value or object that can change needs a single source of truth and a mechanism to enable views to change or observe it. Property wrappers like @State and @Observable enable you to declare how each view interacts with mutable data.
A @State property is a source of truth. In the Observation framework, @State properties can be value types or reference types.
A view that owns a value-type @State property can pass either its value or its binding to its subviews. If it passes a binding to a subview, that subview now has a reference to the source of truth. This allows the subview to update that property’s value or redraw itself when that value changes.
A view that owns a reference-type @State property can pass the object to its subviews, which can pass it on to their subviews. Views can track changes to a reference-type @State object if its class conforms to the Observable protocol. Any change that a view can read from the object causes the view to redraw itself.
Pre-iOS 17
Before iOS 17, @State and @Binding could only be used with value properties, and you’d use @StateObject and @ObservedObject for class objects. To make a class object observable, you’d declare it like this:
class MyViewModelClass: ObservableObject {
@Published var modelArray: [MyModel] = []
}
MyViewModelClass conforms to ObservableObject and publishes modelArray. A view that instantiated MyViewModelClass as a @StateObject or received it as an @ObservedObject from a parent view would react to changes to modelArray by redrawing itself.
Using iOS 17 Observation Framework
An iOS 17 or later app can adopt the Observation framework. Observation:
- Lets you track optionals and collections of objects.
- Updates a view based only on observable properties that the view’s
bodyreads.
Differences from a pre-iOS-17 app are:
- When you define an observable class, instead of conforming to
ObservableObject, attach theObservable()macro@Observableto the type declaration. - Don’t mark observable properties as
@Published. Instead, hide properties that you don’t want views to observe. You’ll try this out in the second demo video. - In views, use
@Statefor both values and objects. - When you pass an observable object to a subview, don’t declare it with any property wrapper if the subview reads the object directly. That is if the subview needs only one-way binding. In the next lesson, you’ll use
@Bindableto support two-way binding.
Follow along with the demo video to see this in action.