Observables
This article aims to explain how observables help or fit in into the use case of sharing data among views.
Before that, we need some context.
When we want to share data among views, we usually use classes instead of structs. The main reason is that whenever we use structs, each view will have its own copy of said struct, so it does not really fit the use case if you would like to share data among views. To be able to share data among views, you need to use classes.
import Combine
class Counter: ObservableObject {
@Published var count = 0
}
The above code contains a class called Counter and it inherits ObservableObject. SwiftUI makes use of the subscriber-publisher model. In this case, the Counter class publishes the count variable.
struct ContentView: View {
@StateObject private var counter = Counter()
var body: some View {
VStack {
Text("Counter: \(counter.count)")
Button("increment in parent") {
counter.count += 1
}
ChildView(counter: counter)
}
.padding()
}
}
In the main view, we declare a Counter object and initialise it.
@StateObject private var counter = Counter()
With that code, we now have access to the Counter class. This allows us to change the value of count in the Counter class. Once changed, the class then publishes said changes to any views listening.
We can even pass the Counter instance down to a child class.
The chain of events are as follows:
- The data is changed in the main view
- The class would publish the changes
- The changes would be reflected in the child view
In other words, the child view only observes and display the changes made to the value.
This would be an example of the child view.
struct ChildView: View {
@ObservedObject var counter: Counter
var body: some View {
VStack {
Text("Counter: \(counter.count)")
Button("increment in child") {
counter.count += 1
}
}
.padding()
}
}
The counter variable is now a parameter for the child view. We do not initialise it here, unlike in the main view. We are only observing from the child view and not actually changing the value. Whatever happens in the main view is then being propagated down to the child view.
This has been the old way. The current code is a handfull. So let's simplify the code.
Let's strip the code down to what we know, without ObservableObject and the @Published keyword.
class Data {
var firstName = "Mirza"
var lastName = "Muhd"
}
The logical next step is to do this.
@State private var data = Data()
Notice that it's not @StateObject but @State.
The nuance with this is that SwiftUI watches the data instance itself and not its contents. It ties back into the whole struct vs classes discussion. This is where @Observable comes into play.
You can continue using the above code. You just have to include a few lines.
import Observation
import SwiftUI
@Observable
class Data {
var firstName = "Mirza"
var lastName = "Muhd"
}
Now, you can use @State private var data = Data() and the code works as expected.
Behind the scenes, SwiftUI is doing tons of heavy lifting. It's lesser code and looks cleaner.
Top comments (0)