SwiftUI中@Binding是语法糖,其底层实现方式为Binding(get:set:)。
@Binding var count: Int
@Binding可以让子视图读取父视图的状态,实现读取、修改父视图的值。
例如:
struct ParentView: View {
@State private var count = 0
var body: some View {
ChildView(count: $count)
}
}
struct ChildView: View {
@Binding var count: Int // 不是复制,而是引用父视图的 count
var body: some View {
Button("增加") {
count += 1
}
}
}
在子视图中创建 @Binding 变量,该变量会引用父视图的 count变量。
ChildView点击按钮修改 count 时,实际上修改的是ParentView 中的 @State count,它们指向同一个“状态源”。
父视图的 count 传递给子视图时,必须使用 $ 表示绑定状态。
使用机制
@Binding 是一个 property wrapper(属性包装器),它的本体是:
struct Binding<Value> {
var get: () -> Value
var set: (Value) -> Void
var wrappedValue: Value {
get { get() }
nonmutating set { set(newValue) }
}
}
也就是说,一个 Binding 本质上就是一对 getter/setter 闭包。
它不存储数据,只是提供一个访问和修改某个外部值的“通道”。
自定义Binding
可以自定义一个Binding类型:
struct MyBinding<T> {
var get: () -> T
var set: (T) -> Void
var wrappedValue: T {
get { get() }
set { set(newValue) }
}
}
创建一个绑定:
var name = "Junyu"
let binding = MyBinding(
get: { name },
set: { name = $0 }
)
binding.wrappedValue = "Fang Junyu"
print(name) // 输出 "Fang Junyu"
当修改Binding的wrappedValue时,实际上是修改Binding本身的数据。
注意事项
1、@Binding 一定要从外部(父视图)传入。子视图不能自己创建它。
如果子视图需要一个默认绑定,可以用 .constant() 创建一个固定值:
TextField("Name", text: .constant("不可编辑"))
2、在父视图中,$变量名 表示把 @State 转换成 Binding,读作“状态的绑定”。
3、SwiftUI 的视图是结构体,不能共享内存,但 Binding 让它们间接共享状态。
总结
@Binding是Binding(get:set:)的语法糖,用于绑定两个视图的参数。
例如:
struct ParentView: View {
@State private var count = 0
var body: some View {
VStack {
ChildView(count: $count)
}
}
}
等价于:
struct ParentView: View {
@State private var count = 0
var body: some View {
let binding = Binding(
get: { count },
set: { count = $0 }
)
VStack {
ChildView(count: binding)
}
}
}
子视图也是如此:
struct ChildView: View {
@Binding var count: Int
var body: some View {
Button("加1") { count += 1 }
}
}
等价于
struct ChildView: View {
var count: Binding<Int>
var body: some View {
Button("加1") { count.wrappedValue += 1 }
}
}
在SwiftUI中,如果访问或修改 @Binding 对象,编译器会自动解包成 . wrappedValue。
@State private var count = 0
Button("Add") {
count += 1 // 实际是 count.wrappedValue += 1
}
而在 Swift 代码中,如果使用 Binding,则需要手动写:
selected?.wrappedValue = ...
相关文章
Swift Binding的闭包实现:https://fangjunyu.com/2024/12/09/swift-binding%e7%9a%84%e9%97%ad%e5%8c%85%e5%ae%9e%e7%8e%b0/
