In SwiftUI, @Bindable is used to create binding to mutable properties of observable class instances, ensuring synchronization between ParentView and ChildView. If I replace @Bindable with @Binding, it simply requires an additional $ sign. Why we need @Bindable if @Binding can achieve the same result that is synchronization of all related views when person.name is modified. What is the key difference in how they work?
▪︎@Bindable , ChildView(person: person)
@Observable
class People {
var name = "No name"
}
struct ChildView: View {
@Bindable var person: People
var body: some View {
VStack {
TextField("...", text: $person.name)
}
}
}
struct ParentView: View {
@State private var person = People()
var body: some View {
VStack {
TextField("...", text: $person.name)
// no `$` sign
ChildView(person: person)
}
}
}
▪︎@Binding , ChildView(person: $person)
@Observable
class People {
var name = "No name"
}
struct ChildView: View {
@Binding var person: People
var body: some View {
VStack {
TextField("...", text: $person.name)
}
}
}
struct ParentView: View {
@State private var person = People()
var body: some View {
VStack {
TextField("...", text: $person.name)
// with `$` sign
ChildView(person: $person)
}
}
}
If Apple have to create a separate property wrapper like @Bindable to achieve two-way binding with @Observable class, I think @Binding should not be fully compatible with @Observable class.
I am expecting the key reason for needing @Bindable rather than using @Binding and really appreciate any answers to figure out the key.
@Binding is compatible with @Observable.
The main difference is that @Binding allows the child view to change entirely which instance of People it is, in addition to getting Bindings of the properties of People.
For example:
struct ChildView: View {
@Binding var person: People
var body: some View {
VStack {
TextField("...", text: $person.name)
Button("Change Person") {
// I cannot do this if 'person' is '@Bindable'
person = People()
person.name = "New Person!"
}
}
}
}
See also the documentation for @State, which also mentions this.
Stateproperties provide bindings to their value. When storing an object, you can get aBindingto that object, specifically the reference to the object. This is useful when you need to change the reference stored in state in some other subview, such as setting the reference tonil[...]
It also says:
However, passing a
Bindingto an object stored inStateisn’t necessary when you need to change properties of that object.
If you need a binding to a specific property of the object, pass either the binding to the object and extract bindings to specific properties where needed, or pass the object reference and use the
Bindableproperty wrapper to create bindings to specific properties.
So use @Binding if the child view needs to change the whole reference to something else (e.g. a totally different instance of People). If you only want Bindings to the object's properties, use @Bindable.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With