I’m a little confused on when to use @StateObject
/@ObservedObject
and when to use @EnvironmentObject
. My confusing is for when the same ViewModel needs to be used in multiple views. For instance, the code below, I need to use SomeViewModel
in all four tab views. In fact, in my current app I’m injecting all my ViewModels to the @EnvironmentObjet as shown in Method 2 below, but I recenlty ran into an issue where some UI controls were not showing and realized that by removing the calls to the view models solves the issue so, I’m now wondering if @StateObject
/@ObservedObject
is the right choice but after thinking about it, the way I’m showing in Method 1, I’m creating multiple instances of the SomeViewModel
and got me wondering if I will end up running into different issues.
What is the most recommended way to use the same viewModel class in multiple SwiftUI views?
View Model Class
class SomeViewModel: ObservableObject{
// some Published variables
// creates, edits, deletes for Core Data objects
}
METHOD 1
Using @StateObject
and @ObservedObject
example:
struct MainView: View {
var body: some View {
TabView(){
TabViewOne()
.tabItem {
Image(systemName: "cart.fill")
Text("Tab1")
}.tag(0)
TabViewTwo()
.tabItem {
Image(systemName: "note.text")
Text("Tab2")
}.tag(1)
TabViewThree()
.tabItem {
Image(systemName: "tag.fill")
Text("Tab3")
}.tag(3)
TabViewFour()
.tabItem {
Image(systemName: "gear")
Text("Tab4")
}.tag(4)
}
}
}
Tab View One
struct TabViewOne: View {
@StateObject var someViewModel = SomeViewModel()
var body: some View {
// passs someViewModel to children views
DetailView(someViewModel: someViewModel)
}
}
struct DetailView: View {
@ObservedObject var someViewModel: SomeViewModel
var body: some View {
// use someViewModel
}
}
Tab View Two
struct TabViewTwo: View {
@StateObject var someViewModel = SomeViewModel()
var body: some View {
// passs someViewModel to children views
DetailView(someViewModel: someViewModel)
}
}
struct DetailView2: View {
@ObservedObject var someViewModel: SomeViewModel
var body: some View {
// use someViewModel
}
}
The same thing is done for the rest of tab views.
METHOD 2
Injecting the view model to the @EnvironmentObject
in the first view of the app example:
@main
struct MyAppName: SwiftUI.App {
@StateObject var someViewModel: SomeViewModel
var body: some Scene {
WindowGroup {
MainView()
.environmentObject(someViewModel)
}
}
}
Tab View One
struct TabViewOne: View {
@EnvironmentObject private var someViewModel: SomeViewModel
var body: some View {
// use someViewModel here
}
}
struct DetailView: View {
@EnvironmentObject private var someViewModel: SomeViewModel
var body: some View {
// use someViewModel here
}
}
Tab View Two
struct TabViewTwo: View {
@EnvironmentObject private var someViewModel: SomeViewModel
var body: some View {
// use someViewModel here
}
}
struct DetailView2: View {
@EnvironmentObject private var someViewModel: SomeViewModel
var body: some View {
// use someViewModel here
}
}
The same thing is done for the rest of tab views.
Just give you more context, SomeViewModel
contains all the creates, edits and deletes for TabViewOne and the rest of views are only referencing one or two functions from it, but the heavy user is TabViewOne.
Thanks
5