我有一个应用程序,它对 REST 服务执行数百个不同的网络调用(HTTP GET 请求)。调用是从应用程序的每个页面完成的,而且调用次数很多。但要求在任何其他网络请求发生之前必须完成两个请求(在启动或唤醒时)。这两个请求的结果是一些配置数据,在所有其他后续请求之前需要这些配置数据。 (这个要求有很多原因)
我有一个用于所有 GET 请求的中央方法。它使用 AFNetworking 和(当然)异步处理程序:
func GET(path: String, var parameters: Dictionary<String, String>? = nil) -> Future<AnyObject!> {
let promise = Promise<AnyObject!>()
manager.GET(path, parameters: parameters, success: { (task: NSURLSessionDataTask!, response: AnyObject!) -> Void in
// some processing...
promise.success(response)
}) { (task: NSURLSessionDataTask!, error: NSError!) -> Void in
// some failure handling...
promise.failure(error)
}
return promise.future
}
现在的问题是 - 如何执行前两个调用并阻止所有其他调用,直到这两个调用成功?明显的解决方案是使用信号量来阻塞线程(不是主线程!),直到这两个调用成功到达,但如果可能的话我想避免这种解决方案。 (因为死锁、竞争条件、如何进行错误处理等......通常的嫌疑)
那么有没有更好的解决方案呢?
同步顺序基本上必须是:
- 第一次通话
- 等待第一个调用的成功响应
- 第二次通话
- 等待第二次调用或成功响应
- 允许以任何顺序进行所有其他调用(异步)
我无法在应用程序的上层执行此逻辑,因为 GET 请求可能来自应用程序的每个部分,因此我需要重写所有内容。我想在这个单个 GET 请求上集中完成此操作。
也许我已经使用的 Promise/Future 模式也是可能的,欢迎任何提示。
谢谢。
最佳答案
有几种方法可以解决此类问题:
- 您可以使用信号量或调度组来使用 GCD(如 the answer you linked to 所示)。
- 您可以将异步
NSOperation
自定义子类与NSOperationQueue
结合使用。 - 或者您可以使用 Promise。
但我通常建议您选择这三个之一,但不要尝试使用现有的 futures/promises 代码引入调度/操作队列模式。人们会建议使用调度/操作队列方法,只是因为这是解决此类问题的一般方法(使用 future 尚未获得普遍接受,并且存在竞争的 Promise/future 库)。但 Promise/Futures 的设计正是为了解决这个问题,如果你正在使用它,就坚持下去吧。
关于调度/操作方法的具体细节,我可以解释为什么我不喜欢 GCD 方法,并尝试说服您使用 NSOperationQueue
方法,但如果您是使用 promise / future 。
不过,这里的挑战是您似乎使用的是旧版本的 Thomvis/BrightFutures。当前版本采用两种通用类型。所以我下面的代码可能不适合你。但我会将其作为建议提供,因为它可能具有说明性。
例如,假设您有一个 loginURL
(第一个请求),以及您想要在之后执行的第二个请求,但随后有一个数组 urls
您希望彼此同时运行,但仅限于前两个请求完成后。使用 BrightFutures 3.2.2,它可能看起来像:
GET(loginURL).flatMap { responseObject -> Future<AnyObject!, NSError> in
return self.GET(secondRequestURL)
}.flatMap { responseObject -> Future<Int, NSError> in
return urls.map { self.GET($0) }.fold(0) { sum, _ in sum + 1 }
}.onSuccess { count in
print("\(count) concurrent requests completed successfully")
}.onFailure { error in
print("not successful: \(error)")
}
从您的代码片段来看,您必须使用旧版本的 BrightFutures,因此上面的内容可能无法按编写的方式工作,但希望这说明了基本思想。使用 BrightFutures 的功能来管理这些异步任务并控制哪些任务是顺序完成的,哪些是并发完成的。
关于ios - 同步网络调用在启动时阻止其他调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35045829/