SwiftUI按索引传递字典到子视图时视图未重新渲染问题
问题原因
你遇到的异常是两个SwiftUI的特性共同作用的结果:
EntityAView中你将入参args声明为了@State属性:@State属于视图内部私有状态,仅会在视图初始化时赋值一次,后续父视图传入新的args时,子视图内部的@State args不会同步更新。onAppear仅会在视图首次挂载到视图树时触发一次:切换索引时SwiftUI默认会复用已有的EntityAView实例,不会重新触发onAppear逻辑,因此name始终是第一次初始化时的赋值结果。
你提到替换为String类型就正常,是因为如果直接在body中读取传入的String参数,没有用@State做中转存储,SwiftUI每次刷新视图都会直接读取最新的传入值,不会出现缓存问题。
修复方案
两种方案都可以保留你现有的字典类型和步进逻辑:
方案1:最小侵入修改,强制视图重建
仅需在父视图调用EntityAView时添加id修饰符,绑定当前索引。每次索引变化时SwiftUI会销毁旧视图、创建新的视图实例,自动触发onAppear逻辑:
EntityAView(args: self.args[currentIndex!]) .id(self.currentIndex!) // 仅新增这一行即可
该方案完全不需要改动子视图代码,适配成本最低。
方案2:遵循SwiftUI状态规范,性能更优
修改EntityAView的属性声明,移除入参的@State包装,同时监听入参变化自动更新展示内容:
struct EntityAView: View { // 直接用let接收父视图传入的参数,不需要@State包装 private let args: [String: Any] @State private var name: String? = nil var body: some View { ZStack { if name == nil { Text("LOADING....") } else { Text(name!) } } .onAppear { updateName() } // 监听args变化,每次传入新参数时更新展示内容 .onChange(of: args) { _ in updateName() } } private func updateName() { guard let raw = args["name"], let _name = raw as? String else { return } name = _name } }
该方案不需要频繁销毁重建视图,运行性能更好。
内容的提问来源于stack exchange,提问作者Muhand Jumah
相关产品推荐
相关产品推荐

