I created a Model like this:
class TestModel: ObservableObject {
@Published var num: Int = 0
}
Model is be used in "Home" view and "Home"s child view "HomeSub"
struct Home: View {
@StateObject var model = TestModel()
var body: some View {
NavigationView(content: {
NavigationLink(destination: HomeSub(model: model)) { Text("\(model.num)") }
})
}
}
struct HomeSub: View {
//1
@StateObject var model = TestModel()
//2
@ObservedObject var model = TestModel()
var body: some View {
VStack {
Text("\(model.num)")
.padding()
.background(Color.red)
Button("Add") {
model.num += 1
}
}
.onChange(of: model.num, perform: { value in
print("homeSub: \(value)")
})
}
}
In HomeSub view, what is the difference between 1 and 2? When I run the project, they have exactly the same behavior.
As you've written it, both @StateObject
and @ObservedObject
are doing the same thing in the child view. But, neither is correct because they are unnecessarily creating a new TestModel
just to toss it and replace it with the one being passed in.
The correct way to write the child view is:
@ObservedObject var model: TestModel
In this case, no initial value is assigned to model
in the child view, which means the caller will have to provide it. This is exactly what you want. One source of truth which is the model
in the parent view.
Also, state variables (both @State
and @StateObject
) should be private
to a view and should always be marked with private
. If you had done this:
@StateObject private var model = TestModel()
in the child view, then you wouldn't have been able to pass the model from the parent view and you would have seen that only @ObservedObject
can be used in this case.
Upon further testing, it seems that Swift/SwiftUI avoids creating the TestModel
in the child view when it is written as @ObservedObject var model = TestModel()
, but that syntax is still misleading to the reader and it should still be written as @ObservedObject var model: TestModel
because that makes it clear that model
is being initialized from somewhere else (that is, from the parent view).