I have a view with a separate view model for it's logic. In my view model I've created a binding and I want the Toggle in my View to reflect and act on this. But it the moment, the view reads the initial state of my binding, but it does not allow me to update it (I can't move the toggle box). And I have no idea why this is.
This is my View (simplified):
public var viewModel: MyViewModel // passed as a dependency to my view
var body: some View {
Toggle("Test", isOn: viewModel.isOn)
}
This is the code in my ViewModel:
public var isOn: Binding<Bool> = .constant(false) {
didSet {
print("Binding in practice!")
}
}
As I said, the code runs, and the initial value for isOn
is respected: if I set it to .constant(true)
or .constant(false)
the checkbox is in the correct state. But I am not allowed to change the checkbox. Also the print()
-statement is never executed. So it seems to me there are 2 problems:
- I cannot change the state for
isOn
- The
didSet
is not executed
Can anyone point me in the right direction?
Edit:
So, actually some of you pointed my in the direction I've already tried and that did not work. In the above writing I simplified my use case, but it's actually a bit more abstract than that: I've got a protocol for my View Model that I use as a dependency. What I've got working now (with binding and observing) is the following:
ViewModelProtocol + ViewModel:
public protocol ViewModelProtocol: ObservableObject {
var isOn: Binding<Bool> { get }
}
public class ViewModel: ViewModelProtocol {
private var _isOn: Bool = false
public var isOn: Binding<Bool> {
Binding<Bool>(
get: { self._isOn },
set: {
self._isOn = $0
// custom code
}
)
}
// More code that has @Published properties
}
View:
struct MyView<Model>: View where Model: ViewModelProtocol {
@ObservedObject var viewModel: Model
var body: some View {
Toggle("Test", isOn: viewModel.isOn)
// More code that uses @Published properties
}
}
Once again, I simplified the example and stripped out all clutter, but with this setup I am able to do what I want. However, I'm still not sure if this is the correct way to do this.
The implementation of making my view generic is based on https://stackoverflow.com/a/59504489/1471590