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

Swift后台计时器异常求助:时分秒显示错误(如00:01:75)

解决Timer应用后台返回后时间显示异常的问题

嘿,我来帮你搞定这个计时器的bug!你遇到的00:01:75这种异常显示,核心问题是时间进位逻辑缺失,咱们一步步拆解修复:

问题根源拆解

  • 后台恢复时的时间差处理错误:getTimeDifference返回的秒数可能大于59(比如后台待了75秒就会返回75),你直接把这个数值硬加到self.sec里,没把超过60的部分转换成分钟,自然会出现秒数溢出。
  • 前台计时的更新逻辑有漏洞:updateLabels里只在sec == 59时才触发进位,这只适合每秒加1的常规场景,但如果sec初始值就大于59(比如后台回来后是75),这个判断根本不会触发,秒数会持续往上堆。

修复方案

第一步:重构时间差计算逻辑

放弃单独相加时分秒的方式,改用总秒数计算,再统一拆分成时、分、秒,自动处理进位。

第二步:修正前台计时更新逻辑

把原来的条件判断改成每次加1秒后,统一检查秒、分的进位(用>=60替代==59,逻辑更健壮)。

修正后的完整代码

override func viewDidLoad() {
    super.viewDidLoad()
    NotificationCenter.default.addObserver(self, selector: #selector(pauseWhenBackground(noti:)), name: UIApplication.didEnterBackgroundNotification, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(willEnterForeground(noti:)), name: UIApplication.willEnterForegroundNotification, object: nil)
}

@objc func willEnterForeground(noti: Notification) {
    guard let savedDate = UserDefaults.standard.object(forKey: "savedTime") as? Date else { return }
    
    // 计算后台停留的总秒数,替代拆分时分秒的方式
    let totalElapsedSeconds = Int(Date().timeIntervalSince(savedDate))
    // 用总秒数更新计时器变量,自动处理进位
    updateTimerWithTotalSeconds(totalElapsedSeconds)
    
    // 重启前台计时器
    self.timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: (#selector(AddWorkTime.updateLabels(t:))), userInfo: nil, repeats: true)
}

// 新增:通过总秒数更新时分秒,自动处理进位逻辑
private func updateTimerWithTotalSeconds(_ addedSeconds: Int) {
    // 计算当前计时器的总秒数
    let currentTotalSeconds = self.hrs * 3600 + self.min * 60 + self.sec
    let newTotalSeconds = currentTotalSeconds + addedSeconds
    
    // 拆分总秒数为时分秒
    self.hrs = newTotalSeconds / 3600
    self.min = (newTotalSeconds % 3600) / 60
    self.sec = newTotalSeconds % 60
    
    // 更新UI显示
    self.time.text = String(format: "%02d : %02d : %02d", self.hrs, self.min, self.sec)
}

@objc func updateLabels(t: Timer) {
    // 先加1秒,再统一处理进位
    self.sec += 1
    
    if self.sec >= 60 {
        self.sec -= 60
        self.min += 1
        
        if self.min >= 60 {
            self.min -= 60
            self.hrs += 1
        }
    }
    
    self.time.text = String(format: "%02d : %02d : %02d", self.hrs, self.min, self.sec)
}

@objc func pauseWhenBackground(noti: Notification) {
    self.timer.invalidate()
    UserDefaults.standard.set(Date(), forKey: "savedTime")
}

func resetContent() {
    removeSavedDate()
    timer?.invalidate()
    self.time.text = "00 : 00 : 00"
    self.sec = 0
    self.min = 0
    self.hrs = 0
}

func removeSavedDate() {
    UserDefaults.standard.removeObject(forKey: "savedTime")
}

关键修改说明

  1. 总秒数计算更可靠:用timeIntervalSince直接获取后台停留的秒数差,转换成整数后和当前计时器总秒数相加,再拆分成时分秒,彻底避免了直接相加时分秒的进位漏洞。
  2. 更新逻辑简化健壮:updateLabels改成先加1秒,再检查秒数是否≥60,满足条件就减60并加1分钟;同理检查分钟数是否≥60,不管秒数初始值是多少,都能正确进位。
  3. 代码安全优化:加了guard let判断savedDate,避免强制解包崩溃;timer?.invalidate()用可选链调用,防止timer为nil时崩溃。

这样修改后,不管后台待多久,返回前台后计时器都会正确显示时间,再也不会出现秒数超过60的异常啦!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 05:37:23