I have a view model that is parent to other children view models. That is:
public class ViewModel: ObservableObject {
@Published var nav = NavigationViewModel()
@Published var screen = ScreenViewModel()
The other children view model, such as nav and screen, all serve a specific purpose. For example, nav’s responsibility is to keep track of the current screen:
class NavigationViewModel: ObservableObject {
// MARK: Publishers
@Published var currentScreen: Screen = .Timeline
}
The ViewModel is instantiated in the App struct:
@main
struct Appy_WeatherApp: App {
// MARK: Global
var viewModel = ViewModel()
// MARK: -
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(viewModel)
}
}
}
And I declare an @EnvironmentObject for it on any view that needs access to it:
@EnvironmentObject var viewModel: ViewModel
Any view referencing a non-object property of ViewModel that is being @Published whose value changes will result in the view to be re-rendered as expected. However, if the currentScreen @Published property of the NavigationViewModel changes, for example, then the view is not being re-rendered.
I know I can make it work if I separate NavigationViewModel from ViewModel, instantiate it at the app level and use it as its own environment object in any views that access any of its published properties.
My question is whether the above workaround is actually the correct way to handle this, and/or is there any way for views to be subscribed to value changes of properties inside child objects of environment objects? Or is there another way that I’ve not considered that’s the recommended approach for what I’m trying to achieve through fragmentation of view model responsibilities?