Reputation: 15726
Given the following...
import SwiftUI
class ViewModel: ObservableObject {
var value: Bool
init(value: Bool) {
self.value = value
}
func update() {
value = !value
}
}
struct A: View {
@ObservedObject let viewModel: ViewModel
init(value: Bool) {
viewModel = ViewModel(value: value)
}
var body: some View {
Text("\(String(viewModel.value))")
.onTapGesture {
viewModel.update()
}
}
}
struct B: View {
@State var val = [true, false, true]
var body: some View {
A(value: val[0])
}
}
How do I get viewModel
to update B
's val
? It looks like I should be able to use @Binding
inside of A
but I can't use @Binding
inside ViewModel
, which is where I want the modification code to run. Then, I don't think I'd need @ObservedObject
because the renders would flow from B
.
Upvotes: 0
Views: 192
Reputation: 49590
If you want to update the value owned by a parent, you need to pass a Binding
from the parent to the child. The child changes the Binding
, which updates the value for the parent.
Then you'd need to update that Binding
when the child's own view model updates. You can do this by subscribing to a @Published
property:
struct A: View {
@ObservedObject var viewModel: ViewModel
@Binding var value: Bool // add a binding
init(value: Binding<Bool>) {
_value = value
viewModel = ViewModel(value: _value.wrappedValue)
}
var body: some View {
Button("\(String(viewModel.value))") {
viewModel.update()
}
// subscribe to changes in view model
.onReceive(viewModel.$value, perform: {
value = $0 // update the binding
})
}
}
Also, don't forget to actually make the view model's property @Published
:
class ViewModel: ObservableObject {
@Published var value: Bool
// ...
}
Upvotes: 1
Reputation:
You either need Binding
, or an equivalent that does the same thing, in ViewModel
. Why do you say you can't use it?
struct A: View {
@ObservedObject var model: Model
init(value: Binding<Bool>) {
model = .init(value: value)
}
var body: some View {
Text(String(model.value))
.onTapGesture(perform: model.update)
}
}
extension A {
final class Model: ObservableObject {
@Binding private(set) var value: Bool
init(value: Binding<Bool>) {
_value = value
}
func update() {
value.toggle()
}
}
}
struct B: View {
@State var val = [true, false, true]
var body: some View {
A(value: $val[0])
}
}
Upvotes: 1