同步网络呼叫在启动时阻止其他呼叫

时间:2016-01-27 19:02:59

标签: ios multithreading swift afnetworking

我有一个应用程序,可以对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
}

现在的问题是 - 如何执行前两个调用并阻止所有其他调用,直到这两个调用成功?显而易见的解决方案是阻塞线程(不是主!)的信号量,直到这两个调用成功到达,但如果可能的话,我想避免这种解决方案。 (因为死锁,竞争条件,如何进行错误处理等等......通常的嫌疑人)

那么有更好的解决方案吗?

同步顺序基本上必须是:

  1. 第一次致电
  2. 等待第一次电话的成功回复
  3. 第二次电话
  4. 等待或成功回复第二次电话
  5. 以任何顺序允许所有其他呼叫(异步)
  6. 我无法在应用程序的上层执行此逻辑,因为GET请求可能来自应用程序的每个部分,因此我需要重写everthing。我想在这个单一的GET请求中集中进行。

    也许这已经可以使用我已经使用的Promise / Future模式,欢迎任何提示。

    感谢。

1 个答案:

答案 0 :(得分:2)

有几种方法可以解决这类问题:

  • 您可以使用信号量或调度组来使用GCD(如the answer you linked to所示)。
  • 您可以将异步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的功能来管理这些异步任务,并控制哪些是顺序完成的,哪些是同时完成的。