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

iOS Swift:如何避免Timer调用invalidate()时触发fire()?

问题分析与解决

你的文档理解没有错

Apple文档关于invalidate()的描述是准确的:调用该方法后,Timer会停止所有后续的自动触发请求,并从RunLoop中移除,不会再被RunLoop调度自动执行。你看到的额外触发并不是invalidate()导致的,而是代码里的手动调用逻辑。

问题根源

看你的startMyTimer()函数:

private func startMyTimer() {
   myTimer = Timer.scheduledTimer(withTimeInterval: 10, repeats: true) { timer in
      print("my timer: Fired \(Date.now.mediumTimeLocalizedDescription)")
   }
   myTimer!.fire() // 这里是关键!
}

每次创建新的Timer后,你都手动调用了fire(),强制Timer立刻执行一次回调。在你3秒后的重启逻辑里:

DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(3)) {
   self.myTimer!.fire()
   print("my timer: invalidating \(Date.now.mediumTimeLocalizedDescription)")
   self.myTimer!.invalidate()
   self.myTimer = nil
   self.startMyTimer() // 这里调用startMyTimer,又会手动触发一次fire
}

调用startMyTimer()时,新创建的Timer会立刻执行fire(),这就是你看到my timer: Fired 14:27:17这条额外输出的原因。

解决办法

根据你的预期输出,你希望重启后的Timer从10秒后才开始触发,所以只需要去掉startMyTimer()里的手动fire()调用即可:

private func startMyTimer() {
   myTimer = Timer.scheduledTimer(withTimeInterval: 10, repeats: true) { timer in
      print("my timer: Fired \(Date.now.mediumTimeLocalizedDescription)")
   }
   // 移除这一行:myTimer!.fire()
}

如果首次启动时需要立刻触发,重启时不需要,可以加个参数区分:

private func startMyTimer(shouldFireImmediately: Bool = true) {
   myTimer = Timer.scheduledTimer(withTimeInterval: 10, repeats: true) { timer in
      print("my timer: Fired \(Date.now.mediumTimeLocalizedDescription)")
   }
   if shouldFireImmediately {
       myTimer!.fire()
   }
}

// 首次启动
startMyTimer()

// 重启时不立刻触发
self.startMyTimer(shouldFireImmediately: false)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 21:35:18