I'm working on a SwiftUI app using the MVVM architecture. I have the problem that I need to pass data from a parent View into its child viewModel, but I'm not sure how to pass a parameter from the view into the viewModel.
The child View which should own the viewModel is here:
struct InstanceView: View {
@ObservedObject var instance: Instance
@StateObject var viewModel = InstanceViewViewModel(instance: instance)
var body: some View {
...
}
}
And this is the viewModel:
class InstanceViewViewModel: ObservableObject {
@ObservedObject var instance: Instance
...
}
Obviously the View doesn't work, I get the error Cannot use instance member 'instance' within property initializer; property initializers run before 'self' is available
If I try using init()
in the View to assign a value to viewModel
:
@ObservedObject var instance: Instance
@StateObject var viewModel: InstanceViewViewModel
init(instance: Instance) {
self.instance = instance
self.viewModel = InstanceViewViewModel(instance: instance)
}
But I get the error Cannot assign to property: 'viewModel' is a get-only property
.
I have read that you should give the viewModel property (instance
) a default value, and then set it in the View with .onAppear()
. However, in my case, Instance
is a Core Data object so I can't really create one to use as a default value.
I also read that I could maybe use _instance = StateObject(wrappedValue: InstanceViewViewModel(instance: instance))
in the View's init, and swiftUI would be smart enough to only initialize the StateObject
once. However I'm pretty sure this is a bad practice.
I also can't use lazy
on a StateObject
So is there any other way to achieve this? Could a solution be somehow getting the value InstanceView is being initialized with on this line:
@StateObject var viewModel = InstanceViewViewModel(instance: instance)
, outside of an init, so I don't need to reference self, like you would do inside of an init? (this is probably a stupid idea)
Or should I be implementing MVVM in a different way?
Thanks!