iOS 15兼容Swift可取消异步延迟:Task.sleep精度问题求解
兼容iOS 15的高精度可取消异步延迟实现方案
问题分析
Task.sleep在长延迟场景下精度不足,核心原因是系统会对后台任务做调度优化,导致实际唤醒时间存在明显偏差。我们需要实现一个兼顾精度、可取消性且兼容iOS 15的异步延迟方案。
优化实现方案
通过结合DispatchSourceTimer与CheckedThrowingContinuation可以满足需求,既保证延迟精度,又支持任务取消,同时适配iOS 15及以上版本。
代码实现
import Foundation @available(iOS 13.0, *) func preciseCancellableDelay(seconds: TimeInterval) async throws { try await withCheckedThrowingContinuation { continuation in // 使用全局高优先级队列保障调度响应速度 let timer = DispatchSource.makeTimerSource(queue: DispatchQueue.global(qos: .userInitiated)) // 设置严格的延迟时间,leeway设为0最小化系统调度误差 timer.schedule(deadline: .now() + seconds, leeway: .nanoseconds(0)) var isCancelled = false // 监听外部任务取消状态 let cancellationTask = Task { try await Task.yield() guard !isCancelled else { return } timer.cancel() continuation.resume(throwing: CancellationError()) } timer.setEventHandler { isCancelled = true cancellationTask.cancel() continuation.resume() } timer.resume() } } // 使用示例 Task { let before = Date.timeIntervalSinceReferenceDate let seconds: TimeInterval = 100 print("> sleeping for \(seconds) seconds...") do { try await preciseCancellableDelay(seconds: seconds) let after = Date.timeIntervalSinceReferenceDate print(String(format: "> slept for %0.3f seconds", after - before)) } catch is CancellationError { print("> delay was cancelled") } catch { print("> unexpected error: \(error)") } }
方案细节说明
- 精度控制:
DispatchSourceTimer支持设置leeway参数,设为.nanoseconds(0)可要求系统尽可能严格按照设定时间触发,大幅降低长延迟场景下的误差。 - 取消机制:通过内部
cancellationTask监听外部任务的取消状态,一旦任务被取消,立即终止计时器并抛出CancellationError,保证取消逻辑的及时性。 - 兼容性:
withCheckedThrowingContinuation和Task均在iOS 13及以上版本支持,完全适配iOS 15。
场景适配建议
- 如果延迟后需要在主线程执行操作,可将
DispatchSourceTimer的队列改为DispatchQueue.main。 - 根据业务场景调整QoS等级:若对精度要求极高但允许消耗更多资源,保留
.userInitiated;若为后台低优先级任务,可改用.background平衡性能与资源占用。
内容的提问来源于stack exchange,提问作者neatchuck
相关产品推荐
相关产品推荐

