Reputation: 1564
As far as I understand, if I need to update the view model from inside a view, I need to make it a binding variable.
The model.
enum Options: Int, Identifiable, Equatable, CaseIterable {
case option1 = 1
case option2 = 2
case option3 = 3
case option4 = 4
var id: String { "\(self.rawValue)" }
}
class TestViewModel: ObservableObject {
var selectedOption = Options.option1
...
}
The view.
struct TestView: View {
@Binding var viewModel: TestViewModel
@State var selectedOption = Options.option1
var body: some View {
Picker("Option 1", selection: $viewModel.selectedOption) {
ForEach(Options.allCases, id: \.id) { value in
Text(value.id)
.tag(value)
}
}
Text("Selected Option: \(viewModel.selectedOption.rawValue)")
Picker("Option 2", selection: $selectedOption) {
ForEach(Options.allCases, id: \.id) { value in
Text(value.id)
.tag(value)
}
}
Text("Selected Option: \(selectedOption.rawValue)")
}
}
How can I make the view refresh using @Binding which is required to update the model?
I come up with this solution which works but it doesn't look good to me.
...
let b = Binding<Options>(
get: {
viewModel.selectedOption
},
set: {
viewModel.selectedOption = $0
selectedOption = $0 // << this forces the view to refresh
}
)
Picker("Speed 1", selection: b) {
ForEach(Options.allCases, id: \.id) { value in
Text(value.id)
.tag(value)
}
}
...
Upvotes: 1
Views: 70
Reputation: 981
I am not sure if you have a valid reason to use ObservableObject
here but you can easily achieve the same results by using a struct
and State
variable:
struct TestViewModel {
var selectedOption = Options.option1
}
struct TestView: View {
@State var viewModel: TestViewModel
var body: some View {
Picker("Option 1", selection: $viewModel.selectedOption) {
ForEach(Options.allCases, id: \.id) { value in
Text(value.id)
.tag(value)
}
}
}
}
Upvotes: 0
Reputation: 257493
The ObservableObject
works in pair with ObservedObject
wrapper. In such case view model becomes source of truth for a view. So...
class TestViewModel: ObservableObject {
@Published var selectedOption = Options.option1 // << here !!
...
}
struct TestView: View {
@ObservedObject var viewModel: TestViewModel
Picker("Speed 1", selection: $viewModel.selectedOption) {
ForEach(Options.allCases, id: \.id) { value in
Text(value.id)
.tag(value)
}
}
Upvotes: 2