Post

Replies

Boosts

Views

Activity

SwiftUI Binding property from view model to a value outside of that view model
I'm having an issue with a Binding property inside of a view model that's being created in another view model. Here is simplified version of 2 views: struct ContentView: View { @StateObject var viewModel = ContentViewModel() var body: some View { VStack { // binding through `@Published var toggleViewModel` ToggleWrapperView(viewModel: viewModel.toggleViewModel) // binding through `var isOnBinding: Binding<Bool>` ToggleWrapperView(viewModel: ToggleViewModel(isOn: viewModel.isOnBinding!, title: "Binding through isOnBinding")) // binding through `@Published var isOn` ToggleWrapperView(viewModel: ToggleViewModel(isOn: $viewModel.isOn, title: "Binding through view")) } .padding() } } struct ToggleWrapperView: View { var viewModel: ToggleViewModel var body: some View { VStack { Toggle(isOn: viewModel.$isOn, label: { Text(viewModel.title + " \(viewModel.isOn)") }) } } } And here are simple view models for the views: class ContentViewModel: ObservableObject { @ObservedObject var dataManager = DataManager() @Published var toggleViewModel: ToggleViewModel! @Published var isOn: Bool = false // Property for the binding in the ContentView private var privateIsOnForBinding: Bool = false var isOnBinding: Binding<Bool>? init() { toggleViewModel = ToggleViewModel(isOn: $dataManager.isOn, title: "Binding from DataManager") initBinding() } func initBinding() { isOnBinding = Binding { self.privateIsOnForBinding } set: { updatedValue in self.privateIsOnForBinding = updatedValue print(self.isOnBinding!) } } } struct ToggleViewModel { @Binding var isOn: Bool let title: String } class DataManager: ObservableObject { @Published var isOn: Bool = false { didSet { print("did set DataManager.isOn \(isOn)") } } } From the ToggleWrapperView examples above only binding created with $viewModel.isOn is working as expected on toggle action. In the example with toggleViewModel I can see that the property in DataManager is being updated (print in the property observer), but the binding itself stays false Binding<Bool>(transaction: SwiftUI.Transaction(plist: []), location: SwiftUI.LocationBox<SwiftUI.(unknown context at $1c5c1c4dc).ObjectLocation<BindingTest.DataManager, Swift.Bool>>, _value: false) And using var isOnBinding: Binding<Bool> gives me the same result, binding is not being updated Binding<Bool>(transaction: SwiftUI.Transaction(plist: []), location: SwiftUI.LocationBox<SwiftUI.FunctionalLocation<Swift.Bool>>, _value: false) This is just a simplified example, but I'd like to understand why 2 versions don't work. I can make the example with toggleViewModel to work if I mark var viewModel: ToggleViewModel as @Binding in the ToggleWrapperView, and remove the @Binding from the isOn property of ToggleViewModel (first example in the view). However I'm trying to have the binding for the isOn between ToggleViewModel and DataManager that's being passed in the ContentViewModel if possible.
5
0
2.1k
Feb ’24