Swift:如何终止循环中启动的多个Timer实例?
如何终止批量创建的Timer任务?
嘿,我懂你的痛点——用循环批量生成了一堆延迟执行的Timer,没给每个单独存变量,现在想一次性叫停所有还没触发的任务对吧?咱们来拆解几个实用的解决方案:
方法一:用数组统一管理所有Timer
这是最直观可靠的方案,你之前担心变量被覆盖?其实只要把每个创建的Timer都塞进一个数组里就行,完全不会冲突:
// 先声明一个数组来存所有创建的Timer var timers = [Timer]() let myString = "stackoverflow" var counter = 0.0 for char in myString { let timer = Timer.scheduledTimer( timeInterval: counter, target: self, selector: #selector(myFunc(_:)), userInfo: String(char), repeats: false ) timers.append(timer) // 把每个Timer加入数组管理 counter += 1.0 } // 终止所有Timer的方法 func stopAllTimers() { timers.forEach { $0.invalidate() } timers.removeAll() // 清空数组,避免内存残留 } @objc func myFunc(_ timer: Timer) { guard let value = timer.userInfo as? String else { return } print("Value: \(value)") }
需要终止的时候,只要调用stopAllTimers(),所有未触发的Timer都会被立刻失效,已经触发过的非重复Timer会自动清理,不用额外处理。
方法二:通过RunLoop查找并终止目标Timer
要是你不想维护数组,也可以利用RunLoop的特性——所有通过scheduledTimer创建的Timer都会加入当前RunLoop的默认模式。我们可以给Timer加个专属标识,然后遍历RunLoop里的Timer来筛选终止:
let myString = "stackoverflow" var counter = 0.0 // 定义一个专属标识,用来区分我们创建的Timer private let timerIdentifier = "StackOverflowCharPrinter" for char in myString { // 把字符和标识一起放进userInfo let userInfo = ["char": String(char), "identifier": timerIdentifier] Timer.scheduledTimer( timeInterval: counter, target: self, selector: #selector(myFunc(_:)), userInfo: userInfo, repeats: false ) counter += 1.0 } // 终止所有带我们标识的Timer func stopAllTimers() { RunLoop.current.enumerateSubmissions { timer, stop in guard let userInfo = timer.userInfo as? [String: Any], let identifier = userInfo["identifier"] as? String, identifier == timerIdentifier else { return } timer.invalidate() } } @objc func myFunc(_ timer: Timer) { guard let userInfo = timer.userInfo as? [String: Any], let value = userInfo["char"] as? String else { return } print("Value: \(value)") }
这种方式不用额外维护数组,但要注意Timer所在的RunLoop模式,如果你的Timer是在自定义模式下创建的,需要对应调整enumerateSubmissions的参数。
方法三:用全局开关控制任务执行(简单快捷)
如果只是不想让myFunc里的打印逻辑执行,而不是严格终止Timer,那加个开关变量就搞定了:
var shouldExecuteTimer = true let myString = "stackoverflow" var counter = 0.0 for char in myString { Timer.scheduledTimer( timeInterval: counter, target: self, selector: #selector(myFunc(_:)), userInfo: String(char), repeats: false ) counter += 1.0 } // 关闭开关,后续Timer触发也不会执行打印 func stopTimerActions() { shouldExecuteTimer = false } @objc func myFunc(_ timer: Timer) { guard shouldExecuteTimer, let value = timer.userInfo as? String else { return } print("Value: \(value)") }
这个方案最快捷,但Timer还是会触发,只是逻辑被跳过了,适合临时禁用任务的场景。
总结推荐
- 要是需要严格终止Timer释放资源,优先选方法一,逻辑清晰且可靠;
- 不想维护数组的话,可以试试方法二;
- 临时禁用任务用方法三就足够。
内容的提问来源于stack exchange,提问作者Jonas0000
相关产品推荐
相关产品推荐

