SwiftUI iOS15 Bug:List刷新动作执行于旧视图实例,求解决方案
解决SwiftUI中refreshable无法获取视图最新参数的问题
问题描述
在SwiftUI中给List添加refreshable修饰符后,当List所在的子视图(TestChildView)因父视图传入的参数更新而重新实例化时,下拉触发的刷新动作仍然会使用旧视图实例的参数值,无法获取当前最新的参数。例如点击递增按钮后,列表内容已更新为新的参数值,但下拉刷新时打印的还是初始值。
解决方案
方法1:使用.id()强制视图完全重建
在父视图中给TestChildView添加.id(myVar)修饰符,让参数变化时子视图被完全销毁并重新创建,确保refreshable闭包绑定到最新的参数值:
struct TestParentView: View { @State var myVar = 0 var body: some View { VStack { Text("increment") .onTapGesture { myVar += 1 } TestChildView(myVar: myVar) .id(myVar) // 添加这一行 } } }
方法2:子视图内部维护同步状态
在子视图中用@State变量同步父视图传入的参数,让refreshable闭包捕获这个可变的状态变量,确保能获取最新值:
struct TestChildView: View { let myVar: Int @State private var currentMyVar = 0 // 新增内部状态 struct Item: Identifiable { var id: String { val } let val: String } var list: [Item] { [Item(val: "a \(myVar)"), Item(val: "b \(myVar)"), Item(val: "c \(myVar)")] } var body: some View { VStack { List(list) { elem in Text(elem.val) }.refreshable { print("myVar: \(currentMyVar)") // 使用内部状态 } } .onChange(of: myVar) { newValue in currentMyVar = newValue // 参数变化时更新内部状态 } .onAppear { currentMyVar = myVar // 初始化时同步参数 } } }
问题原因
SwiftUI的refreshable修饰符通过设置环境中的刷新动作实现,当视图因参数更新重新计算body时,旧视图实例的刷新动作并未被替换,导致闭包捕获的仍是旧的参数值。两种解决方案分别通过强制视图重建或绑定可变状态变量,让刷新闭包能获取到最新的参数。
内容的提问来源于stack exchange,提问作者Travis
相关产品推荐
相关产品推荐

