iOS网络请求在串行队列中

nar*_*ero 5 multithreading grand-central-dispatch ios swift ios9

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

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

client.save(object) { error in
     print(error)
}
client.delete(object)
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

在客户端执行下一个请求之前,我将如何确保完成每个请求(及其闭包).我也需要能够支持链式请求(所以在一个闭包中我会再发一个请求).

Ham*_*ish 10

这可以通过信号量轻松完成

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

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")
        })

    })

}
Run Code Online (Sandbox Code Playgroud)

我希望这可以帮助你!


小智 6

这可以使用带有等待方法的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
    }
}
Run Code Online (Sandbox Code Playgroud)


小智 2

您可以尝试NSOperationsNSOperationQueue. 一个很好的介绍: http: //nshipster.com/nsoperation/

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

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

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

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