SwiftUI中子结构体更新时父级关联计算属性无法刷新问题
问题根因
Entry为值类型结构体,@Published对数组的变更校验仅对比元素的存储属性,你当前代码中duration是计算属性,不参与等值校验。只要id、name两个存储属性没有变化,系统就会判定Entry实例无变更,不会触发视图重绘。- 手动调用
get()方法重新赋值entries时,新老数组的元素存储属性一致,系统依旧会判定数组无变更,跳过更新逻辑。
优化实现方案
方案1:自定义Equatable逻辑(改动最小)
手动实现Entry的Equatable协议,让等值校验包含duration的计算结果:
struct Entry: Identifiable, Equatable { var id = UUID().uuidString var name = "" var duration: Int { let total = try! dbc.scalar(tableFlight.filter(db.entry == id).select(db.duration.total)) return Int(total) } static func == (lhs: Entry, rhs: Entry) -> Bool { lhs.id == rhs.id && lhs.name == rhs.name && lhs.duration == rhs.duration } }
调整后每次调用get()重新赋值entries时,只要duration发生变化就会触发视图更新。
方案2:改为存储属性主动更新(性能更优)
计算属性每次访问都会执行SQL查询,列表元素较多时会产生性能损耗,建议将duration改为存储属性,数据变更时主动更新:
- 调整
Entry定义:
struct Entry: Identifiable { var id = UUID().uuidString var name = "" var duration: Int // 改为存储属性 }
- 调整视图模型:
class EntryModel: ObservableObject{ static let shared = EntryModel() @Published var entries = [Entry]() init(){ get() } func get(){ // 查询Entry时直接关联计算duration,赋值给存储属性 entries = // SQLite查询时关联Flight表计算总时长,直接生成完整Entry实例 } // Flight数据变更后调用此方法刷新对应Entry的时长 func updateDuration(for entryId: String) { guard let index = entries.firstIndex(where: { $0.id == entryId }) else { return } let total = try! dbc.scalar(tableFlight.filter(db.entry == entryId).select(db.duration.total)) entries[index].duration = Int(total) } }
每次增删改Flight数据后,调用updateDuration(for: 关联的entryId)即可触发对应视图更新,不需要全量重查整个Entry数组。
内容的提问来源于stack exchange,提问作者Clifton Labrum
相关产品推荐
相关产品推荐

