Swift 6中如何用Task替代DispatchSemaphore.wait(timeout:)实现事件检测?
基于Task替代DispatchSemaphore实现超时事件检测的方案
需求回顾
检测10秒时间窗口内是否有回调事件触发:
- 事件可多次触发,只需判断是否发生过一次
- 事件触发时需提前终止等待并返回
true - 超时未触发则返回
false
原代码问题
原使用DispatchSemaphore的实现在转为async函数后,Swift 6会抛出错误:
Instance method 'wait' is unavailable from asynchronous contexts; Await a Task handle instead; this is an error in Swift 6
这是因为semaphore.wait()会阻塞线程,违背了async/await的非阻塞设计原则,因此Swift 6明确禁止这种用法。
推荐的Swift 6实现方案
使用withCheckedContinuation结合Task取消机制,实现非阻塞的超时检测,同时支持提前终止:
func checkForEvents() async -> Bool { await withCheckedContinuation { continuation in // 保存事件回调引用,用于后续清理 var eventHandler: ((Event) -> Void)? // 启动超时任务:10秒后返回false let timeoutTask = Task { try? await Task.sleep(nanoseconds: 10_000_000_000) continuation.resume(returning: false) eventService.onEvent = nil } // 绑定事件回调:触发后立即返回true并取消超时任务 eventHandler = { _ in continuation.resume(returning: true) timeoutTask.cancel() eventService.onEvent = nil } eventService.onEvent = eventHandler // 处理外部取消场景:清理资源 continuation.onCancel = { timeoutTask.cancel() eventService.onEvent = nil } } }
实现关键点
- 非阻塞等待:通过
withCheckedContinuation将回调式事件转为async/await兼容的异步逻辑,不会阻塞线程 - 提前终止:事件触发时立即调用
continuation.resume()返回结果,并取消超时Task避免无效等待 - 资源清理:无论是事件触发、超时还是外部取消,都会重置
eventService.onEvent并取消超时Task,避免内存泄漏和回调残留 - 线程安全:如果
eventService.onEvent在多线程环境下被调用,可根据实际情况添加同步机制(比如用Atomic变量或串行队列)
对原替代方案的改进
你之前的Task.sleep方案无法提前终止的核心问题是没有监听事件触发并取消等待,上述方案通过绑定事件回调+Task取消完美解决了这个问题。
内容的提问来源于stack exchange,提问作者jacksoor
相关产品推荐
相关产品推荐

