SwiftUI中.refreshable闭包无法正确访问model?这是Bug吗?
问题分析与解决方案
这并非refreshable的预期行为,问题根源在于值类型Model的传递机制与SwiftUI视图更新逻辑的交互冲突。
问题本质
Model是值类型(struct),调用mutating方法修改selectedValue时,本质是生成新的Model实例并替换原属性。虽然@Observable类会检测到这个赋值操作并触发ContentView重新渲染,让NewView拿到新的Model实例,但refreshable的异步闭包可能捕获了NewView初始化时的旧Model副本——当ContentView重新渲染生成新的NewView实例时,旧实例的refreshable闭包可能仍被系统保留,导致下拉刷新时访问的是旧值。- 按钮的点击闭包是同步执行的,每次
NewView重新创建时都会绑定新的Model实例,因此能拿到最新值。
修复方案
方案1:将Model改为引用类型(class)
把Model从struct改为class,让所有视图共享同一个实例,无论何时访问都是最新值:
@Observable class Model { var selectedValue = 0 func setValue(_ value: Int) { self.selectedValue = value } } @Observable class ContentViewController { var model = Model() func setValue(_ value: Int) { self.model.setValue(value) } }
方案2:简化状态管理,直接在ContentViewController中维护状态
去掉Model结构体,将selectedValue直接作为ContentViewController的属性,避免值类型传递带来的副本问题:
@Observable class ContentViewController { var selectedValue = 0 func setValue(_ value: Int) { self.selectedValue = value } } // 修改ContentView中的NewView调用 struct ContentView: View { @State private var cntrl = ContentViewController() @State private var counter = 0 var body: some View { VStack { Button { counter += 1 cntrl.setValue(counter) } label: { Text("Increase value") } Text("Selected value local: \(counter)") Text("Selected value cntrl: \(cntrl.selectedValue)") NewView(selectedValue: cntrl.selectedValue) } } } // 修改NewView struct NewView:View { let selectedValue: Int @State private var valueSetByFunc = 0 var body: some View { VStack { Button { whatIsTheValue() } label: { Text("Call func") } List { Text("Value set by func: \(valueSetByFunc)") }.refreshable { whatIsTheValue() } } } private func whatIsTheValue() { valueSetByFunc = selectedValue } }
方案3:让Model成为可观察值类型(iOS 17+)
给Model添加@Observable宏,确保其内部属性变化能被SwiftUI正确感知:
@Observable struct Model { var selectedValue = 0 mutating func setValue(_ value: Int) { self.selectedValue = value } }
此时ContentViewController的model属性变化会准确触发视图更新,NewView每次都会拿到最新的Model实例,refreshable闭包也会捕获最新值。
总结
值类型的状态传递在SwiftUI中需要注意视图更新时机,异步闭包(如refreshable)容易捕获旧的副本。改用引用类型或简化顶层状态管理,能更可靠地保证状态一致性。
内容的提问来源于stack exchange,提问作者matyasl
相关产品推荐
相关产品推荐

