My question is probably the result of a misunderstanding but I can't figure it out, so here it is:
When using a component like a TextField or any other component requiring a binding as input
TextField(title: StringProtocol, text: Binding<String>)
And a View with a ViewModel, I naturally thought that I could simply pass my ViewModel @Published
properties as binding :
class MyViewModel: ObservableObject {
@Published var title: String
@Published var text: String
}
// Now in my view
var body: some View {
TextField(title: myViewModel.title, text: myViewModel.$text)
}
But I obviously can't since the publisher cannot act as binding. From my understanding, only a @State
property can act like that but shouldn't all the @State
properties live only in the View and not in the view model? Or could I do something like that :
class MyViewModel: ObservableObject {
@Published var title: String
@State var text: String
}
And if I can't, how can I transfer the information to my ViewModel when my text is updated?
You were almost there. You just have to replace myViewModel.$text
with $myViewModel.text
.
class MyViewModel: ObservableObject {
var title: String = "SwiftUI"
@Published var text: String = ""
}
struct TextFieldView: View {
@StateObject var myViewModel: MyViewModel = MyViewModel()
var body: some View {
TextField(myViewModel.title, text: $myViewModel.text)
}
}
TextField
expects a Binding
(for text
parameter) and StateObject
property wrapper takes care of creating bindings to MyViewModel
's properties using dynamic member lookup.