SwiftUI绑定@Binding
SwiftUI绑定@Binding

SwiftUI绑定@Binding

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/

   

如果您认为这篇文章给您带来了帮助,您可以在此通过支付宝或者微信打赏网站开发者。

欢迎加入我们的 微信交流群QQ交流群,交流更多精彩内容!
微信交流群二维码 QQ交流群二维码

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注