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
相关产品推荐
相关产品推荐

