我有一个应用程序,可以对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请求可能来自应用程序的每个部分,因此我需要重写everthing。我想在这个单一的GET请求中集中进行。
也许这已经可以使用我已经使用的Promise / Future模式,欢迎任何提示。
感谢。
答案 0 :(得分:2)
有几种方法可以解决这类问题:
NSOperation
自定义子类与NSOperationQueue
结合使用。但我通常建议您选择这三种中的一种,但不要尝试使用您现有的期货/承诺代码引入调度/操作队列模式。人们会建议调度/操作队列方法,因为这是人们通常如何解决这类问题(使用期货尚未得到普遍接受,并且存在竞争的承诺/期货库)。但承诺/期货旨在解决这个问题,如果您正在使用它,只需坚持下去。
关于调度/操作方法的具体细节,我可以解释为什么我不喜欢GCD方法,并试图说服你使用NSOperationQueue
方法,但这有点没有实际意义。你正在使用承诺/期货。
但是,这里面临的挑战是您似乎使用旧版本的Thomvis / BrightFutures。当前版本对于泛型有两种类型。所以下面的代码可能不适合你。但我会按照建议提供,因为它可能是说明性的。
例如,让我们假设您有loginURL
(第一个请求),以及之后要执行的第二个请求,但后来有一个数组urls
你想要彼此同时运行,但只有在前两个请求完成后才能运行。使用3.2.2的BrightFutures,它可能看起来像:
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的功能来管理这些异步任务,并控制哪些是顺序完成的,哪些是同时完成的。