如何等到所有 NSOperations 完成?
How to wait until all NSOperations is finished?
我有以下代码:
func testFunc(completion: (Bool) -> Void) {
let queue = NSOperationQueue()
queue.maxConcurrentOperationCount = 1
for i in 1...3 {
queue.addOperationWithBlock{
Alamofire.request(.GET, "https://httpbin.org/get").responseJSON { response in
switch (response.result){
case .Failure:
print("error")
break;
case .Success:
print("i = \(i)")
}
}
}
//queue.addOperationAfterLast(operation)
}
queue.waitUntilAllOperationsAreFinished()
print("finished")
}
输出为:
finished
i = 3
i = 1
i = 2
但我预计会出现以下情况:
i = 3
i = 1
i = 2
finished
那么,为什么 queue.waitUntilAllOperationsAreFinished() 不等待?
我建议您使用 KVO 并观察队列何时完成所有任务,而不是阻塞当前线程直到所有操作完成。或者您可以使用依赖项。看看this SO问题
您添加到队列中的每个操作都会立即执行,因为 Alamofire.request
只是 returns 而无需等待响应数据。
另外,这里还有死锁的可能。由于 responseJSON
块默认在主队列中执行,通过调用 waitUntilAllOperationsAreFinished
阻塞主线程将完全阻止它执行完成块。
首先,为了解决死锁问题,您可以告诉 Alamofire 在不同的队列中执行完成块,其次,您可以使用 dispatch_group_t
对异步 HTTP 请求的数量进行分组,并保持主线程等待组中的所有请求完成执行:
let queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)
let group = dispatch_group_create()
for i in 1...3 {
dispatch_group_enter(group)
Alamofire.request(.GET, "https://httpbin.org/get").responseJSON(queue: queue, options: .AllowFragments) { response in
print(i)
dispatch_async(dispatch_get_main_queue()) {
// Main thread is still blocked. You can update the UI here but it will take effect after all HTTP requests are finished.
}
dispatch_group_leave(group)
}
}
dispatch_group_wait(group, DISPATCH_TIME_FOREVER)
print("finished")
检查是否所有操作完成 - 我们可以使用 KVO 来观察队列中的操作数。不幸的是,operations 和 operationCount 目前都 deprecated..!
因此使用依赖项的以下选项是安全的。
检查几个操作是否完成 - 使用依赖项:
创建一个名为 "finishOperation" 的最终操作,然后将依赖项添加到所有其他必需的操作。这样,"finishOperation" 只会在相关操作完成时执行。检查此 answer 以获取代码示例。
我有以下代码:
func testFunc(completion: (Bool) -> Void) {
let queue = NSOperationQueue()
queue.maxConcurrentOperationCount = 1
for i in 1...3 {
queue.addOperationWithBlock{
Alamofire.request(.GET, "https://httpbin.org/get").responseJSON { response in
switch (response.result){
case .Failure:
print("error")
break;
case .Success:
print("i = \(i)")
}
}
}
//queue.addOperationAfterLast(operation)
}
queue.waitUntilAllOperationsAreFinished()
print("finished")
}
输出为:
finished
i = 3
i = 1
i = 2
但我预计会出现以下情况:
i = 3
i = 1
i = 2
finished
那么,为什么 queue.waitUntilAllOperationsAreFinished() 不等待?
我建议您使用 KVO 并观察队列何时完成所有任务,而不是阻塞当前线程直到所有操作完成。或者您可以使用依赖项。看看this SO问题
您添加到队列中的每个操作都会立即执行,因为 Alamofire.request
只是 returns 而无需等待响应数据。
另外,这里还有死锁的可能。由于 responseJSON
块默认在主队列中执行,通过调用 waitUntilAllOperationsAreFinished
阻塞主线程将完全阻止它执行完成块。
首先,为了解决死锁问题,您可以告诉 Alamofire 在不同的队列中执行完成块,其次,您可以使用 dispatch_group_t
对异步 HTTP 请求的数量进行分组,并保持主线程等待组中的所有请求完成执行:
let queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)
let group = dispatch_group_create()
for i in 1...3 {
dispatch_group_enter(group)
Alamofire.request(.GET, "https://httpbin.org/get").responseJSON(queue: queue, options: .AllowFragments) { response in
print(i)
dispatch_async(dispatch_get_main_queue()) {
// Main thread is still blocked. You can update the UI here but it will take effect after all HTTP requests are finished.
}
dispatch_group_leave(group)
}
}
dispatch_group_wait(group, DISPATCH_TIME_FOREVER)
print("finished")
检查是否所有操作完成 - 我们可以使用 KVO 来观察队列中的操作数。不幸的是,operations 和 operationCount 目前都 deprecated..!
因此使用依赖项的以下选项是安全的。
检查几个操作是否完成 - 使用依赖项:
创建一个名为 "finishOperation" 的最终操作,然后将依赖项添加到所有其他必需的操作。这样,"finishOperation" 只会在相关操作完成时执行。检查此 answer 以获取代码示例。