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

Swift并发:如何让任务等待特定数据加载完成后执行?

解决方案:用Actor实现Token刷新的串行化与请求等待

完全可以实现你的需求,Actor是Swift并发中解决这类共享资源同步、避免重复操作的最佳方案,它天然保证所有方法调用串行执行,同时可以维护一个正在进行的Token刷新任务引用,让后续请求自动等待刷新完成后再执行。

改造后的代码实现

actor APIManager {
    // 跟踪正在进行的Token刷新任务,避免重复触发
    private var tokenRenewalTask: Task<Void, Error>?
    
    func execute<R: ResponseProtocol>(request: RequestProtocol, response: R) async throws -> R.Value {
        let session = getURLSession()
        var urlRequest: URLRequest = request.buildURLRequest()

        let (data, urlResponse) = try await session.data(for: urlRequest)

        if let httpURLResponse = urlResponse as? HTTPURLResponse,
           httpURLResponse.statusCode == 401 {
            try await handleTokenRenewal()
            // 刷新Token后,重新构建带新Token的请求并重试
            urlRequest = request.buildURLRequest()
            let (retryData, _) = try await session.data(for: urlRequest)
            return try decode(data: retryData)
        }

        return try decode(data: data)
    }
    
    /// 处理Token刷新逻辑,确保同一时间只有一个刷新任务在执行
    private func handleTokenRenewal() async throws {
        if let existingTask = tokenRenewalTask {
            // 已有刷新任务,等待其完成
            try await existingTask.value
        } else {
            // 没有正在进行的刷新任务,创建新任务
            let task = Task {
                try await renewBearerToken()
            }
            tokenRenewalTask = task
            
            do {
                try await task.value
            } catch {
                // 刷新失败,抛出错误并清空任务引用
                tokenRenewalTask = nil
                throw error
            }
            // 刷新成功,清空任务引用
            tokenRenewalTask = nil
        }
    }
    
    // 原有的辅助方法保持不变
    private func getURLSession() -> URLSession {
        // 返回你的URLSession实例
        URLSession.shared
    }
    
    private func renewBearerToken() async throws {
        // 实现Token刷新逻辑
    }
    
    private func decode<R: ResponseProtocol>(data: Data) throws -> R.Value {
        // 实现数据解码逻辑
        try JSONDecoder().decode(R.Value.self, from: data)
    }
}

关键逻辑说明

  1. Actor改造:将APIManager从class改为actor,确保所有异步方法调用都是串行执行的,避免多Task同时修改共享状态(比如tokenRenewalTask)。
  2. 刷新任务跟踪:通过tokenRenewalTask变量记录当前是否有正在进行的Token刷新操作:
    • 当第一个请求遇到401时,创建刷新任务并执行;
    • 后续请求遇到401时,发现已有刷新任务,直接等待该任务完成,无需重复发起刷新。
  3. 错误处理:如果Token刷新失败,会抛出错误并清空任务引用,避免后续请求一直等待无效任务。
  4. 重试请求:刷新Token后,需要重新构建带新Token的请求(因为原请求的Token已经失效),再发起重试。

为什么不用TaskGroups?

TaskGroups的核心用途是并发执行多个子任务并汇总结果,而你的场景需要的是串行化关键操作(Token刷新)+ 让其他请求等待该操作完成,Actor的串行执行模型更贴合这个需求,代码也更简洁易维护。

内容的提问来源于stack exchange,提问作者JorisT

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 14:47:21