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

TimelineView停止更新:点击Indulge按钮后UI不再刷新问题

问题与修复:Indulge按钮点击后UI停止更新

问题现象

首次点击Indulge按钮后,UI出现异常:

  • indulgences数组计数不再递增
  • 计算属性pctIntervalComplete停止更新,进度条也不再变化

根因分析

问题出在Habit结构体的Hashable实现上:

  • 当前仅手动实现了==方法,仅比较habitId
  • Swift自动合成的hash(into:)方法会计算所有属性(包括indulgences数组)的哈希值
  • 调用addIndulgence()修改indulgences后,Habit的哈希值发生变化,ForEach无法识别这是同一个实例,导致UI与状态的绑定断裂,后续更新无法触发刷新

修复方案

手动实现hash(into:)方法,仅基于habitId计算哈希值,保持与==逻辑一致,确保Habit的身份判断完全由唯一的habitId决定:

struct Habit: Hashable {
    static func == (lhs: Habit, rhs: Habit) -> Bool {
        return lhs.habitId == rhs.habitId
    }
    
    // 手动实现hash(into:),仅关联habitId
    func hash(into hasher: inout Hasher) {
        hasher.combine(habitId)
    }
    
    // 以下原有代码保持不变
    public let habitId: UUID
    public var habitName: String
    public var indulgences: [Indulgence]
    
    public var daysInterval: Int
    public var hoursInterval: Int
    public var minsInterval: Int
    public var secsInterval: Int
    public var daysIncrease: Int
    public var hoursIncrease: Int
    public var minsIncrease: Int
    public var secsIncrease: Int
    
    private let minutesToSeconds: Int = 60
    private let hoursToSeconds: Int = 3600
    private let daysToSeconds: Int = 86400
    
    public var pctIntervalComplete: Double {
        guard let latestIndulgence = indulgences.last else {
            return 0.0
        }
        
        let currentInterval = Date.now.timeIntervalSinceReferenceDate - latestIndulgence.timestamp.timeIntervalSinceReferenceDate
        
        return currentInterval / targetIntervalInSeconds
    }
    
    public var isIntervalComplete: Bool {
        return pctIntervalComplete >= 1.0
    }
    
    private var targetIntervalInSeconds: TimeInterval {
        return TimeInterval((daysInterval * daysToSeconds) + (hoursInterval * hoursToSeconds) + (minsInterval * minutesToSeconds) + secsInterval)
    }
    
    init(habitId: UUID = UUID(), habitName: String) {
        self.habitId = habitId
        self.habitName = habitName
        indulgences = [Indulgence]()
        daysInterval = 0
        hoursInterval = 0
        minsInterval = 1
        secsInterval = 0
        daysIncrease = 0
        hoursIncrease = 0
        minsIncrease = 1
        secsIncrease = 0
    }
    
    mutating public func addIndulgence() {
        var i = Indulgence(habitId: self.habitId)
        indulgences.append(i)
    }
}

修复原理

让hash(into:)仅依赖habitId后,无论Habit的其他属性如何变化,其哈希值始终保持一致,ForEach能持续识别同一个实例,状态更新就能正常触发UI刷新。

内容的提问来源于stack exchange,提问作者Legion

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 10:55:33