iOS开发:24小时促销计时器无法停止,代码调试求助
解决24小时促销计时器停止逻辑失效的问题
问题根源
- 错误的时间对比逻辑:每次调用
updateCountDown都会重新生成newDate(当前时间+35秒),这个日期和你存在UserDefaults里的waitingDate完全无关,导致判断结束的逻辑根本没用到正确的截止时间。 - 时间差计算方向错误:
Calendar.current.dateComponents([.second], from: newDate!, to: Date())计算的是当前时间比newDate晚多少秒,但newDate是当前时间+35秒,所以这个差值是负数,永远不可能大于35,自然不会进入停止分支。 - 未持有定时器实例:即使判断到倒计时结束,也没有办法停止定时器,它会继续每秒触发一次。
修改后的完整代码
class SLTimer { // 计算剩余时间,处理可选值并补零优化格式 func timeLeftExtended(date: Date) -> String { let cal = Calendar.current let now = Date() let components = cal.dateComponents([.hour, .minute, .second], from: now, to: date) let hour = components.hour ?? 0 let minute = components.minute ?? 0 let second = components.second ?? 0 return String(format: "%02d : %02d : %02d", hour, minute, second) } func updateCountDown() -> String? { guard let waitingDate = UserDefaults.standard.value(forKey: "waitingDate") as? Date else { // 首次启动设置截止时间(测试用35秒,正式环境改为86400秒即24小时) let endDate = Calendar.current.date(byAdding: .second, value: 35, to: Date())! UserDefaults.standard.set(endDate, forKey: "waitingDate") return timeLeftExtended(date: endDate) } let now = Date() // 直接判断当前时间是否超过截止时间 if now >= waitingDate { UserDefaults.standard.removeObject(forKey: "waitingDate") return "stop" } else { return timeLeftExtended(date: waitingDate) } } } class ViewController: UIViewController { // 持有定时器实例,用于停止倒计时 private var countdownTimer: Timer? private let slTimer = SLTimer() override func viewDidLoad() { super.viewDidLoad() startCountdown() } private func startCountdown() { // 初始化重复定时器 countdownTimer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(updateButtonTitle), userInfo: nil, repeats: true) // 立即更新按钮标题,避免延迟1秒显示 updateButtonTitle() } @objc private func updateButtonTitle() { guard let timeString = slTimer.updateCountDown() else { return } if timeString == "stop" { saleButton.setTitle("促销结束", for: .normal) // 停止定时器并释放资源 countdownTimer?.invalidate() countdownTimer = nil } else { saleButton.setTitle(timeString, for: .normal) } } }
关键改动说明
- SLTimer优化:
- 仅在首次启动时设置并存储截止时间,后续统一使用该时间判断是否结束。
- 直接对比当前时间和截止时间,逻辑更直观,避免时间差计算错误。
- 处理可选值避免崩溃,同时用
String(format:)给数字补零,让倒计时格式更规范(如00:00:05)。
- ViewController优化:
- 新增
countdownTimer属性持有定时器实例,方便在倒计时结束时调用invalidate()停止。 - 复用
slTimer实例,避免每次创建新对象。 - 启动时立即更新按钮标题,解决定时器第一次触发延迟1秒的问题。
- 倒计时结束时,更新按钮为“促销结束”并停止定时器,避免无效触发。
- 新增
内容的提问来源于stack exchange,提问作者user1342352532
相关产品推荐
相关产品推荐

