I have a parent view which contains two child views. Each child view gets passed a different EnvironmentObject from the parent view. As a representation for all kinds of different changes, the second child view contains a Button which can be used to call a function in its ViewModel which then is supposed to change a variable in the ViewModel of the first child view.
struct ParentView: View {
@StateObject var viewModel_1: ViewModel_1
@StateObject var viewModel_2: ViewModel_2
var body: some View {
ZStack {
ChildView_1()
.environmentObject(viewModel_1)
ChildView_2()
.environmentObject(viewModel_2)
}
}}
struct ChildView_1: View {
@EnvironmentObject var viewModel_1: ViewModel_1
var body: some View {
...
}}
struct ChildView_2: View {
@EnvironmentObject var viewModel_2: ViewModel_2
var body: some View {
Button(action: {
viewModel_2.changeValue_in_ViewModel_1(value: 1)
}, label: {
Text("Tap to change value")
})
}}
class ViewModel_1: ObservableObject {
@Published var someValue: Int = 0
func changeValue(value: Int) -> Void {
self.someValue = value
}
}
class ViewModel_2: ObservableObject {
func changeValue_in_ViewModel_1(value: Int) -> Void {
//something like viewModel_2.changeValue(value: value)
}
}
Is there a way to make those two ViewModels able to communicate with each other?
Thanks!
2
Answers
It would be solved simply by ViewModel_2 referencing ViewModel_1.
However, it is not necessary to refer to all ViewModel_1, so you can separate only the desired logic using protocol and let ViewModel_2 own it.
This is the sample code for the above explanation.
Searching for dependency injection can yield a lot of information about it.
We don’t actually use view model objects in SwiftUI. The
View
struct is a view model already, being a value type it’s more efficient and less error prone than an object but the property wrappers make it behave like an object, SwiftUI diffs the View struct and it creates/updates actual UIView/NSViews on screen for us. If you use actual view model objects you’ll get bugs and face the problems that you are experiencing.You can group related
@State
vars into their own struct and usemutating func
for logic. That way it can be tested independently but the best thing is any chance to a property of the struct is detected by SwiftUI as a change to the whole struct which makes its dependency tracking super fast.environmentObject
is designed to hold a store object that contains the model structs (usually in arrays) in@Published
properties. There isn’t usually more than oneenvironmentObject
. This object is usually responsible for persisting or syncing the model data.