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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 17:04:58