Search code examples
iosswiftnsoperationnsoperationqueue

How to wait until all NSOperations is finished?


I have the following code:

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

and output is:

finished
i = 3
i = 1
i = 2

but I expect the following:

i = 3
i = 1
i = 2
finished

So, why queue.waitUntilAllOperationsAreFinished() don't wait?


Solution

  • Each operation you've added into queue is immediately executed because Alamofire.request simply returns without waiting for the response data.

    Furthermore, there is a possibility of deadlock there. Since responseJSON block is executed within the main queue by default, blocking the main thread by calling waitUntilAllOperationsAreFinished will prevent it from executing the completion block at all.

    First, in order to fix the deadlock issue, you can tell Alamofire to execute the completion block in a different queue, second, you can use dispatch_group_t to group the number of asynchronous HTTP requests and keep the main thread waiting till all those requests in the group finish executing:

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