iOS网络请求在串行队列中

时间:2016-01-22 18:33:17

标签: ios multithreading swift ios9 grand-central-dispatch

在我的View Controller中,我使用名为Client的类进行网络调用。客户端基本上是Alamofire(AFNetworking)网络调用的包装器,所以我有保存(POST),get(GET)和删除(DELETE)方法。

每个视图控制器都有一个实例变量客户端,用户可以创建,编辑和删除对象,如下所示:

client.save(object) { error in
     print(error)
}
client.delete(object)

我想确保对于给定的客户端,不会同时删除/修改同一个对象。客户端可能有多个实例处理相同的用户可编辑对象。

我的想法是创建一个客户端的所有实例将用于排队请求的串行队列,但是我遇到了每个函数的闭包问题。我希望异步完成请求(以避免阻塞主线程)和Alamofire使用闭包,但我希望客户端将请求视为同步,以便按接收顺序执行它们并等待所有闭包完成后再继续下一个避免任何冲突的请求。

我的客户端保存方法如下所示:

dispatch_async(self.serialQueue) {
    self.httpClient.post("url", object) { error in
         // handle errors, maybe make another request, etc
    }
}

如何在客户端执行下一个请求之前完成确保每个请求(及其闭包)的完成。我需要能够支持链式请求(因此在闭包中我会再提出请求)。

3 个答案:

答案 0 :(得分:9)

使用信号量

可以轻松完成

您所要做的就是让信号量被捕获到闭包中,并在完成给定的网络任务后发出信号。

let semaphore = dispatch_semaphore_create(1);

for i in 0...10 {

    dispatch_async(serialQueue, {

        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER) // wait for the previous network task to complete. you could also setup a timeout here.

        self.doNetworkTask({error in

            // do error handling & make new requests

            dispatch_semaphore_signal(semaphore) // once done, signal the semaphore to start next task.
            print("network task \(i) done")
        })

    })

}

我希望这可以帮到你!

答案 1 :(得分:2)

您可以尝试在NSOperations中使用异步NSOperationQueue。 一个好的介绍:http://nshipster.com/nsoperation/

通常你是NSOperation的子类,覆盖其main()方法来执行你的代码并将其添加到NSOperationQueue。在这种情况下,你有 与使用串行队列时相同的问题:如果操作执行异步任务,它将在您的taks实际完成之前释放队列。

但是,当子类化NSOperation时,您可以使用KVO控制其状态,以便在异步任务完成之前不会将其视为已完成。

这是一个使用here代码的运行示例,您可以将其粘贴到游乐场中: https://gist.github.com/doschi/c628e4ad431dffc57d13

也许你可以用它作为解决问题的起点。

答案 2 :(得分:1)

使用 DispatchGroup 等待方法可以轻松完成此操作:

// move on secondary thread
DispatchQueue.global().async {

    let dispatchGroup = DispatchGroup()

    dispatchGroup.enter()
    client.save(object) { error in
        print(error)
        dispatchGroup.leave()
    }
    dispatchGroup.wait()

    dispatchGroup.enter()
    client.delete(object) {
        dispatchGroup.leave()
    }
    dispatchGroup.wait()

    // move back on main thread
    DispatchQueue.main.async {
        // completion
    }
}