我在AWS上有一个由HTTPPost请求触发的步骤函数。该功能可能需要几秒钟才能完成。如果用户将应用程序放回后台,我希望继续执行,并在用户将应用软件放回前台后(如果执行完成(正确导航到下一个屏幕。
我的API客户端端点如下所示:
func connect<OutputType: Decodable>(to request: URLRequestConvertible, decoder: JSONDecoder) -> AnyPublisher<Result<OutputType, Error>, Never> {
var request = request.asURLRequest()
if let token: String = KeychainWrapper.standard.string(forKey: "apiToken") {
request.addValue(token, forHTTPHeaderField: "Authorization")
}
let configuration = URLSessionConfiguration.default
configuration.waitsForConnectivity = true
let session = URLSession(configuration: configuration)
return session.dataTaskPublisher(for: request)
.tryMap({ (data, response) -> Data in
guard let response = response as? HTTPURLResponse else { throw NetworkError.invalidResponse }
guard 200..<300 ~= response.statusCode else {
throw NetworkError.invalidStatusCode(statusCode: response.statusCode)
}
return data
})
.decode(type: OutputType.self, decoder: decoder)
.map(Result.success)
.catch { error -> Just<Result<OutputType, Error>> in Just(.failure(error)) }
.receive(on: DispatchQueue.main)
.eraseToAnyPublisher()
}
我想知道实现这一呼吁的最佳实践。我目前正在使用下面的beginBackgroundTask。
func makeRequest() {
DispatchQueue.global(qos: .userInitiated).async {
self.backgroundTaskID = UIApplication.shared.beginBackgroundTask (withName: "Request Name") {
UIApplication.shared.endBackgroundTask(self.backgroundTaskID!)
self.backgroundTaskID = .invalid
}
<implementation>
}
}
然而,implementation
只有在我嵌套了DispatchQueue.main.async块的情况下才有效,在这些块中,我在发出HTTP请求后执行更多的逻辑(比如在收到响应后确定下一个屏幕的导航(。
这是最好的方法吗?在DispatchQueue.global块中有几个不同的嵌套DispatchQueQueue.main.async块可以吗?我应该将.receive(on: )
发布到DispatchQueue.global吗?
您根本不必将此后台任务分派到后台队列。(不要将"后台任务"(指应用程序状态(与"后台队列"(指使用哪些线程(混为一谈。(
此外,正如文档所说,过期处理程序闭包在主线程上运行:
系统在主线程上同步调用处理程序,暂时阻止应用程序的挂起。
因此,无论如何,您确实希望在主线程上保留与backgroundTaskID
的所有交互,否则您将不得不实现一些其他同步机制。
作为一种良好的做法,请确保在异步请求完成时结束后台任务(而不是依赖于过期/超时关闭(。