SwiftUI TextField忽略绑定、按下回车键重置值问题咨询
问题原因
你遇到的问题是由两个核心错误用法导致的:
- 视图模型没有遵循
ObservableObject协议:普通类的内部属性变化不会被SwiftUI感知,无法触发视图刷新。 - 错误使用
@State修饰引用类型:@State是设计用来存储值类型的包装器,只会监控值本身的变化,对于引用类型只会存储其内存地址,不会监控地址指向对象的内部属性变更。
当你按下回车键时,绑定的set方法确实会执行,底层s属性的值也会修改,但因为SwiftUI没有收到视图需要刷新的通知,不会重新计算body内容,自然不会调用绑定的get方法读取最新值,TextField会继续使用内部缓存的旧值,看起来就像被重置了,你也看不到Getting binding的打印输出。
修正方案
修改代码如下即可解决问题:
import SwiftUI // 1. 让ViewModel遵守ObservableObject协议 class ViewModel: ObservableObject { let defaultS = "Default String" // 2. 给需要触发刷新的属性加上@Published包装器 @Published var s = "" var sBinding: Binding<String> { .init(get: { print("Getting binding \(self.s)") return self.s.count > 0 ? self.s : self.defaultS }, set: { print("Setting binding") self.s = $0 }) } } struct ContentView: View { // 3. 用@StateObject持有ObservableObject类型的视图模型 @StateObject private var vm = ViewModel() var body: some View { TextField("S:", text: vm.sBinding) .padding() } }
修改点说明:
ObservableObject协议是SwiftUI监听引用类型对象变化的基础,只有遵守该协议的对象才能被SwiftUI监控变更。@Published会在属性值变更时自动发送重绘通知,触发关联视图的刷新逻辑。@StateObject是专门用来持有ObservableObject类型实例的属性包装器,会自动监听对象发出的刷新通知,收到通知后重新计算body,此时就会调用绑定的get方法读取最新值,TextField就会正常更新。如果需要兼容macOS 10.15,可以将@StateObject替换为@ObservedObject,但注意@ObservedObject不会持有对象的所有权,需要外部保证对象不会被意外销毁。
内容的提问来源于stack exchange,提问作者aciniglio
相关产品推荐
相关产品推荐

