I need to access variables from the EnvironmentObject in plain (non-view) Swift classes–just read them, not update them (all updates occur within views). I’ve read in a few answers such as here and here that making your environment object a singleton works well for this. Does this look like a valid way to do it?
It definitely works, I’m just worried there is something about the approach that could break the management of the publishing. I know that updating the variables via the shared
instance would break the publishing, but if you’re just reading values, should this be OK?
PROBLEM CODE
class AppViewModel: ObservableObject {
@Published var lastName = ""
}
struct MyApp: App {
@StateObject var appViewModel = AppViewModel()
var body: some Scene {
WindowGroup {
MainView()
.environmentObject(appViewModel)
}
}
}
struct ContentView: View {
@EnvironmentObject var myAppViewModel: AppViewModel
var body: some View {
TextField("enter last name", text: $myAppViewModel.lastName)
}
}
class PlainSwiftClass {
@EnvironmentObject var appViewModel: AppViewModel // <-- DOESN'T WORK, NOT A VIEW
func getLastName() {
print(appViewModel.lastName)
}
}
SUGGESTED FIX
class AppViewModel: ObservableObject {
static let shared = AppViewModel() // <-- Adding shared instance
@Published var lastName = ""
}
struct MyApp: App {
@StateObject var appViewModel = AppViewModel.shared // <-- Instantiating from the shared instance
var body: some Scene {
WindowGroup {
MainView()
.environmentObject(appViewModel)
}
}
}
struct ContentView: View {
@EnvironmentObject var myAppViewModel: AppViewModel
var body: some View {
// No changes here. You can still update the @StateObject as before.
TextField("enter last name", text: $myAppViewModel.lastName)
}
}
class PlainSwiftClass {
func getLastName() {
print(AppViewModel.shared.lastName) // <--- THIS WORKS
}
}