Based on this answer: What is the difference between ObservedObject and StateObject in SwiftUI
And the Apple documentation code here: https://developer.apple.com/documentation/swiftui/managing-model-data-in-your-app
In SwiftUI app, a @StateObject
property wrapper should be used when a View
instantiates the object itself, so that the object won't be recreated during a view update.
If the object is instantiated somewhere else, an @ObservedObject
wrapper should be used instead.
However, there is a fine line which makes it a bit unclear: what if the object is instantiated somewhere else, but "injected" to the View
and then the view is the sole owner / holder of that object? Should it be @StateObject
or @ObservedObject
?
Sample code to get the point illustrated:
import SwiftUI
import Combine
import Foundation
struct ViewFactory {
func makeView() -> some View {
let viewModel = ViewModel()
return NameView(viewModel)
}
}
final class ViewModel: ObservableObject {
@Published var name = ""
init() {}
}
struct NameView: View {
// Should this be an `@ObservedObject` or `@StateObject`?
@ObservedObject var viewModel: ViewModel
init(_ viewModel: ViewModel) {
self.viewModel = viewModel
}
var body: some View {
Text(viewModel.name)
}
}
Based on this article: https://www.hackingwithswift.com/quick-start/swiftui/whats-the-difference-between-observedobject-state-and-environmentobject
There is one important difference between @StateObject and @ObservedObject, which is ownership – which view created the object, and which view is just watching it.
The rule is this: whichever view is the first to create your object must use @StateObject, to tell SwiftUI it is the owner of the data and is responsible for keeping it alive. All other views must use @ObservedObject, to tell SwiftUI they want to watch the object for changes but don’t own it directly.
it appears that if the View
to instantiate the ViewModel
, it has to be declared with @StateObject
. My code is very similar, the only difference is that the ViewModel
is created elsewhere, but the View
"owns" it after the initialization.
CodePudding user response:
This is a really interesting question. There's some subtle behavior going on here.
First, notice that you can't just change @ObservedObject
to @StateObject
in NameView
. It won't compile:
struct NameView: View {
@StateObject var viewModel: ViewModel
init(_ viewModel: ViewModel) {
self.viewModel = viewModel
// ^