You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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改为存储属性,数据变更时主动更新:

  1. 调整Entry定义:
struct Entry: Identifiable {
    var id = UUID().uuidString
    var name = ""
    var duration: Int // 改为存储属性
}
  1. 调整视图模型:
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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 14:48:02