Code Block struct NewsView: View { @EnvironmentObject var store: Store @StateObject private var vm: NewsViewModel init() { self._vm = StateObject(wrappedValue: NewsViewModel(self._store.wrappedValue.newsApi)) } var body: some View { if vm.show == true { HStack { Image("round-flag") .resizable() .aspectRatio(contentMode: .fit) .frame(width: 20) .rotationEffect(.degrees(-28)) Text(self.vm.news?.subject ?? "") .instaStylePrimary() Button { vm.show = false } label: { Image(systemName: "xmark") .instaStylePrimary() .frame(width: 12) .foregroundColor(.gray) } } } } }
Initializing a @StateObject from an @EnvironmentObject
As far as I know, the answer currently seems to be NO.Is this even possible?
You may need to go back to the place where your EnvironmentObject is instantiated, and add another function to instantiate the StateObject.
So what's the solution for using MVVM in a setup where you're using EnvironmentObject to pass in access to the model?
I'm thinking of something like Core Data where you can use an EnvironmentObject to pass in an NSManagedObjectContext. You can't create an @EnvironmentObject ViewModel in init because the EnvironmentObject isn't set yet. And the EnvironmentObject property's didSet doesn't fire so you can't do it there.
Creating the ViewModel in onAppear works but seems a bit clumsy. Is that the best way to do this?
Yes, this seems clumsy at the moment. As noted, the environmentObject is not available in init.
It is possible to assign a temporary value on declaration:
@State private var vm: NewsViewModel = /// some temporary value
...then assign the true value in onAppear:
.onAppear {
vm = /// it's true value, which can reference the environmentObject
}
It's not pretty, but it works.