We needed to bind to the @Published
in a ParentView's @StateObject
being used as a ViewModel. I told my coworker we needed to pass in the entire ViewModel to an @ObservedObject
in the ChildView, since everything I've read about SwiftUI describes the parent-child data relationships like this:
Parent View | Child View |
---|---|
@State | @Binding |
@StateObject | @ObservedObject |
@Published (within the @StateObject) | DOESN'T EXIST |
He insisted we could just pass in the @Published
alone to the ChildView
's @Binding
and it would work. Lo and behold, he was right. In the example code below is the documented way to use @Binding
, along with passing the entire @StateObject
down into an @ObservedObject
and binding to the @Published
directly (which I thought was the only way you could/should bind to an @Published
), and passing the @Published
directly into the @Binding
, which surprisingly does work. You can see in the sample pic that when you type in any of the 3 TextField
's, the updates appear immediately in the parent view, proving that the @Binding
works with all 3 approaches.
Is this a fluke about binding to the @Published
directly? Or an undocumented-but-valid approach? Why isn't this taught as a standard approach?
import SwiftUI
class MyViewModel: ObservableObject {
@Published var publishedStr1 = "I am publishedStr1"
@Published var publishedStr2 = "I am publishedStr2"
}
struct ParentView: View {
@State var stateStr = "I am stateStr"
@StateObject var myViewModel = MyViewModel()
var body: some View {
VStack {
ChildView(stateStr: $stateStr,
myViewModel: myViewModel,
// Why don't I ever see examples using this technique
// of passing the @Published directly to an @Binding?
// It clearly works.
publishedStr2: $myViewModel.publishedStr2)
Text(stateStr)
Text(myViewModel.publishedStr1)
Text(myViewModel.publishedStr2)
}
}
}
struct ChildView: View {
@Binding var stateStr: String
@ObservedObject var myViewModel: MyViewModel
@Binding var publishedStr2: String
var body: some View {
VStack {
TextField("Binding to State", text: $stateStr)
.textFieldStyle(RoundedBorderTextFieldStyle())
TextField("Binding to ObservedObject",
text: $myViewModel.publishedStr1)
.textFieldStyle(RoundedBorderTextFieldStyle())
TextField("Binding to ObservedObject's Published",
text: $publishedStr2)
.textFieldStyle(RoundedBorderTextFieldStyle())
}
}
}