SwiftUI中在函数内访问@State变量取值不正确问题求助
问题原因与解决方案
核心原因
- 最常见的诱因是自定义
blinkBorder修饰符的异常操作:你给Image绑定了$leftRollEditing到blinkBorder的on参数,如果这个修饰符内部在动画执行、视图重绘过程中意外修改了绑定值,或是非预期重置了绑定值,就会导致你读取到的leftRollEditing不是预期的最新值。 - 其次是SwiftUI视图重绘引发的状态读取时序问题:
@State是托管在SwiftUI运行时的值类型属性,它的更新默认会触发视图重绘,如果你在updateRoll执行的同时刚好处于视图重绘周期内,重绘未完成时读取@State可能会拿到上一次渲染的旧值。 - 还有概率较高的场景:你未列出的代码逻辑中存在其它同时修改
leftRollEditing的操作,比如全局手势、父视图状态同步、onChange回调等,在你点击Edit Left Roll和点击Dice1按钮的间隙,状态被意外修改。
修复方案
- 第一步先注释掉
.blinkBorder(on: $leftRollEditing)这行代码验证问题来源,如果注释后状态读取恢复正常,直接排查blinkBorder的内部实现,确保它不会在非预期时机修改绑定值即可。 - 第二步如果排除修饰符问题,可将
@State替换为@StateObject托管的类对象属性,规避值类型状态在视图重绘时的读取时序问题,改造示例如下:
// 定义状态托管类 class ViewModel: ObservableObject { @Published var leftRollEditing = false } // 改造Home视图 struct Home: View { @StateObject private var vm = ViewModel() var body: some View { // ... 原有代码,所有用到leftRollEditing的地方替换为vm.leftRollEditing,绑定用$vm.leftRollEditing HStack { Button { updateRoll() } label: { Image("Dice1") } } HStack { VStack { Image("myImage") .padding() .blinkBorder(on: $vm.leftRollEditing) Text("MyText") } } HStack { Button { vm.leftRollEditing = true } label: { Text("Edit Left Roll") } } } func updateRoll() { if vm.leftRollEditing { vm.leftRollEditing = false //... 其他逻辑代码 } } }
- 如果替换为类托管状态后仍存在问题,可以在所有修改
leftRollEditing的位置添加打印日志,排查是否有未预期的状态修改逻辑,示例如下:
Button { vm.leftRollEditing = true print("设置leftRollEditing为true") } label: { Text("Edit Left Roll") } func updateRoll() { print("updateRoll读取到的leftRollEditing:\(vm.leftRollEditing)") if vm.leftRollEditing { vm.leftRollEditing = false //... 其他逻辑代码 } }
内容的提问来源于stack exchange,提问作者C0D3
相关产品推荐
相关产品推荐

