I realize that @StateObject is deprecated in favor of Observable. However if I were to be in a codebase that was trying to limit themselves to old versions of iOS I would like to understand this better.
@MainActor
class ViewModel: ObservableObject {
// @Published properties here
}
struct MainView: View {
@StateObject var viewModel: ViewModel = ViewModel()
var body: some View {
SubView(viewModel: viewModel)
}
}
struct SubView: View {
@StateObject var viewModel: ViewModel
}
As I understand it there is nothing wrong with doing it this way. I could use a binding but that is a bit overkill considering that ViewModel is a reference type.
What I am hoping to understand is what if SubView had something it needed to do in its init method? How would you write passing in that ObservedObject properly.
struct SubView: View {
@StateObject var viewModel: ViewModel
init(viewModel: ViewModel) {
self.viewModel = viewModel // ERROR: Cannot assign to property: 'viewModel' is a get-only property
// Something else important you needed to do in init like make a string de-bouncer
}
}
Even if you use self._viewModel
you get an error. These errors make sense... How to resolve them... Not sure.
StateObject
is a source of truth, ObservedObject
and EnvironmentObject
are for passing around.
The SubView
should be @ObservedObject
.
The main difference between StateObject
and ObservedObject
is lifecycle.
@StateObject
is assigned "storage" within SwiftUI that survives View
reinitialization, which can happen at any time.
@ObservedObject
does not have the ability to survive redraws and without a source of truth like StateObject
or an object from FetchRequest
the objects get recreated and often cause memory leaks.