如何暂停DispatchQueue调度的任务?游戏暂停按钮实现求助
用DispatchWorkItem轻松实现任务的暂停与恢复
嘿,这个问题我之前做游戏时也踩过坑!直接用DispatchQueue.main.asyncAfter确实没法直接取消已调度的任务,不过用DispatchWorkItem就能完美解决,而且比你计划的记录时间再重新调度要更简洁可控。
核心思路
DispatchWorkItem是一个可取消的任务封装,你可以把要执行的逻辑放进这个item里,然后用队列调度它;当需要暂停时,直接调用item的cancel()方法就能阻止它执行,同时我们只需要记录剩余的延迟时间,恢复时重新调度这个任务就行。
具体实现步骤
- 在你的类中添加几个属性,用来保存任务、剩余延迟和调度截止时间:
class YourGameClass { var ongoing: Bool = true var pendingDisposeTask: DispatchWorkItem? var remainingDelay: TimeInterval = 0 var taskDeadline: DispatchTime? // 你的dispose方法 func dispose() { // 这里是你原来的dispose逻辑 } }
- 替换原来的调度代码,用
DispatchWorkItem来封装任务:
// 假设这是你原来触发调度的地方,delay是传入的延迟时间 func scheduleDisposeTask(with delay: TimeInterval) { remainingDelay = delay // 创建WorkItem,注意用[weak self]避免循环引用 let task = DispatchWorkItem { [weak self] in guard let self = self, self.ongoing else { return } self.dispose() } pendingDisposeTask = task taskDeadline = .now() + delay // 调度任务 DispatchQueue.main.asyncAfter(deadline: .now() + delay, execute: task) }
- 实现暂停逻辑:取消当前任务,并计算剩余的延迟时间
func pauseDisposeTask() { // 取消任务,确保它不会再执行 pendingDisposeTask?.cancel() pendingDisposeTask = nil // 计算剩余延迟时间 guard let deadline = taskDeadline else { return } let remainingNanoSeconds = deadline.rawValue - DispatchTime.now().rawValue remainingDelay = max(0, TimeInterval(remainingNanoSeconds) / TimeInterval(NSEC_PER_SEC)) taskDeadline = nil }
- 实现恢复逻辑:用剩余的延迟时间重新调度任务
func resumeDisposeTask() { guard remainingDelay > 0, ongoing else { return } let task = DispatchWorkItem { [weak self] in guard let self = self, self.ongoing else { return } self.dispose() } pendingDisposeTask = task taskDeadline = .now() + remainingDelay DispatchQueue.main.asyncAfter(deadline: .now() + remainingDelay, execute: task) }
注意事项
- 一定要用
[weak self]在WorkItem的闭包里,否则会导致你的游戏类实例无法被释放,造成内存泄漏。 - 取消任务后,记得把
pendingDisposeTask设为nil,避免持有已取消的任务实例。 - 恢复时要检查
ongoing状态,确保符合你的业务逻辑。
这样你就能通过暂停按钮调用pauseDisposeTask(),恢复时调用resumeDisposeTask(),完美实现任务的停止与恢复啦!
内容的提问来源于stack exchange,提问作者Pablo
相关产品推荐
相关产品推荐

