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

iOS开发中Timer函数间隔异常及倒计时逻辑错误问题求助(附代码)

嘿,我帮你找出代码里的问题啦,咱们一步步来解决:

核心问题梳理
  • 同步循环碰异步Timer的坑:你用的for _ in 1...5是同步执行的,它根本不会等countdown()里的倒计时跑完,会瞬间把5次迭代全部执行完。所以你看到i直接变成1(其实最后会跳到0),因为循环里的i -= 1眨眼间就执行了5次,UI根本来不及更新显示中间值。
  • 全局time没重置+多Timer打架:每次倒计时结束后你没把time恢复成10秒,而且循环里多次调用countdown()会创建好几个Timer同时跑,它们一起修改time,就会出现5、0、-2这种乱跳的数值。
  • Timer没管好:开始新倒计时前没停掉之前的Timer,导致多个Timer同时工作,数值自然乱套。
修正后的代码

我调整了逻辑,用“完成一次倒计时再触发下一次”的异步方式,完美匹配你的需求:

import UIKit

class ViewController: UIViewController {
    @IBOutlet weak var displayTime: UILabel!
    @IBOutlet weak var displayI: UILabel!
    
    var timer: Timer?
    let totalRepeats = 5 // 固定重复5次
    var currentRepeat = 0 // 当前迭代次数
    let initialCountdownTime = 10 // 固定10秒倒计时
    
    @IBAction func startButton(_ sender: Any) {
        // 点击开始时先重置状态
        currentRepeat = 0
        startNextRound()
    }
    
    func startNextRound() {
        // 已经完成5次的话就停止
        guard currentRepeat < totalRepeats else {
            displayTime.text = "全部完成!"
            return
        }
        
        // 更新迭代次数显示(从5往1减)
        currentRepeat += 1
        displayI.text = String(totalRepeats - currentRepeat + 1)
        
        // 重置倒计时数值并更新UI
        var remainingTime = initialCountdownTime
        displayTime.text = String(remainingTime)
        
        // 先停掉之前可能存在的Timer,避免冲突
        timer?.invalidate()
        
        // 用闭包形式的Timer,更安全也更直观
        timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { [weak self] timer in
            remainingTime -= 1
            self?.displayTime.text = String(remainingTime)
            
            if remainingTime == 0 {
                timer.invalidate()
                // 当前倒计时结束,启动下一轮
                self?.startNextRound()
            }
        }
    }
    
    // 页面销毁时记得停掉Timer,防止内存泄漏
    deinit {
        timer?.invalidate()
    }
}
关键改进说明
  • 用currentRepeat追踪当前是第几次迭代,每次倒计时完成后自动调用startNextRound()开启下一次,实现了“等上一轮跑完再跑下一轮”的逻辑,解决了同步循环的问题。
  • 每次开启新倒计时都会把remainingTime重置为10秒,而且先停掉之前的Timer,确保同一时间只有一个Timer在工作,不会出现数值乱跳的情况。
  • 用闭包版的Timer替代selector版,不仅代码更简洁,还通过[weak self]避免了内存泄漏的风险。
  • 页面销毁时在deinit里停止Timer,让代码更健壮。

这样运行后,就会按照你想要的逻辑:先显示i=5,同时从10倒计时到0,然后自动切换到i=4再从10倒计时到0,直到完成5次迭代~

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 15:57:35