为什么UIViewRepresentable的Coordinator中Binding读取值始终为初始值
UIViewRepresentable 绑定读取异常成因解析
核心原因
SwiftUI 中所有遵循View协议的类型都是值类型结构体,UIViewRepresentable也不例外,它的生命周期和 Coordinator 完全不同:
- 当外层绑定的
@State状态发生变化时,SwiftUI 会基于最新状态重新构造一个全新的NativeTextView实例,原有旧实例不会被更新,直接被废弃。 - Coordinator 是类类型,生命周期和底层的UIKit视图绑定,只会在首次调用
makeUIView时生成一次,后续状态更新不会重建Coordinator。
各现象的具体解释
- 旧版代码读取不到最新值的原因
你在makeCoordinator方法中把初始化阶段的Binding存入了Coordinator,后续Coordinator持有的永远是最初版本旧实例携带的Binding。旧的NativeTextView实例不会被SwiftUI同步最新状态,所以读取这个旧Binding的值永远只能拿到初始化时的数值。 - 写操作依然能触发刷新的原因
Binding本质是对外部状态源的读写代理,它的写路径直接指向最外层@State的真实存储地址,即使是旧实例携带的Binding,执行写操作时依然可以穿透到外部状态源,触发外层UI刷新。 - 新版代码生效的原因
updateUIView方法是每次状态更新、SwiftUI生成新的NativeTextView实例后都会触发的系统回调,你在这个回调里传入的self是当前最新的结构体实例,它的text属性已经和外部最新状态同步,所以读取这个实例的属性就能拿到正确值。
推荐最佳实践
常规实现中不需要把Binding或者UIViewRepresentable实例存在Coordinator里,直接在updateUIView回调中把最新的属性值赋值给UIKit视图即可,Coordinator只负责把UIKit的事件回调转换成对Binding的写操作即可,示例如下:
struct NativeTextView: UIViewRepresentable { @Binding var text: String func makeUIView(context: Context) -> UITextField { let view = UITextField() view.borderStyle = .roundedRect view.addTarget( context.coordinator, action: #selector(Coordinator.updateText(sender:)), for: .editingChanged ) return view } func updateUIView(_ uiView: UITextField, context: Context) { // 直接用最新的self.text赋值即可,不需要走Coordinator存的值 uiView.text = text } func makeCoordinator() -> Coordinator { Coordinator($text) } class Coordinator: NSObject { @Binding var text: String init(_ text: Binding<String>){ _text = text } @objc func updateText(sender: UITextField){ text = sender.text ?? "" } } }
内容的提问来源于stack exchange,提问作者Lumentus
相关产品推荐
相关产品推荐

