Swift 并发:推迟任务直到加载某些数据

问题描述 投票:0回答:1

我已经使用 Swift Concurrency 2 年了,但不知道如何解决这种情况。

在名为

APIManager
的类中,有一个执行网络调用的execute方法。 当服务器响应 401 时,需要刷新不记名令牌并重试调用。

看起来大概是这样的:

class APIManager {
   func execute<R: ResponseProtocol>(request: RequestProtocol, response: R) async throws -> R.Value {
       let session = getURLSession()
       let urlRequest: URLRequest = request.buildURLRequest()

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

       if let httpURLResponse = urlResponse as? HTTPURLResponse,
          httpURLResponse.statusCode == 401 {
          try await renewBearerToken()
          return try await execute(request: request, response: response)
       }

       return decode(data: data)
   }
}

此类只有一个实例(注入到每个服务中)。 任务在应用程序周围随机触发(例如单击按钮),并调用此方法。

我想要实现的是,每当类加载数据时,尤其是刷新令牌时,请确保任何其他并行触发的任务在完成调用之前等待其完成(否则也可能有遇到 401 的风险)。

对于是否以及如何执行有什么想法吗?任务组、演员?

swift concurrency swift-concurrency
1个回答
0
投票

基本思想是,您将保存对不记名令牌的

Task
的引用,并且
await
它:

class APIManager {
    private var bearerTask: Task<Void, Error>?
    
    func execute<R: ResponseProtocol>(request: RequestProtocol, response: R) async throws -> R.Value {
        _ = try await bearerTask?.value
        
        let session = getURLSession()
        let urlRequest: URLRequest = request.buildURLRequest()
        
        let (data, urlResponse) = try await session.data(for: urlRequest)
        
        if let httpURLResponse = urlResponse as? HTTPURLResponse, httpURLResponse.statusCode == 401 {
            bearerTask = Task { try await renewBearerToken() }
            return try await execute(request: request, response: response)
        }
        
        return decode(data: data)
    }
}

就个人而言,我会让 API 管理器成为

actor
(或将其隔离到全局参与者)以避免
bearerTask
上的竞争。

但是您可以让多个 API 调用都等待相同的

bearerTask

© www.soinside.com 2019 - 2024. All rights reserved.