简体   繁体   中英

Completion handlers and Operation queues

I am trying to do the following approach,

let operationQueue = OperationQueue()
operationQueue.maxConcurrentOperationCount = 10

func registerUser(completionHandler: @escaping (Result<Data, Error>) -> Void) -> String {
        self.registerClient() { (result) in
        switch result {
            case .success(let data):
                self.downloadUserProfile(data.profiles)
            case .failure(let error):
                return self.handleError(error)
        }
    }
  }

func downloadUserProfile(urls: [String]) {
    for url in urls {
        queue.addOperation {
            self.client.downloadTask(with: url)
        }
    }
}

I am checking is there anyway I can get notified when all operations gets completed and then I can call the success handler there.

I tried checking the apple dev documentation which suggests to use

queue.addBarrierBlock {
   <#code#>
}

but this is available only from iOS 13.0

Pre iOS 13, we'd use dependencies. Declare a completion operation, and then when you create operations for your network requests, you'd define those operations to be dependencies for your completion operation.

let completionOperation = BlockOperation { ... }

let networkOperation1 = ...
completionOperation.addDependency(networkOperation1)
queue.addOperation(networkOperation1)

let networkOperation2 = ...
completionOperation.addDependency(networkOperation2)
queue.addOperation(networkOperation2)

OperationQueue.main.addOperation(completionOperation)

That having been said, you should be very careful with your operation implementation. Do I correctly infer that downloadTask(with:) returns immediately after the download task has been initiated and doesn't wait for the request to finish? In that case, neither dependencies nor barriers will work the way you want.

When wrapping network requests in an operation, you'd want to make sure to use an asynchronous Operation subclass (eg https://stackoverflow.com/a/32322851/1271826 ).

The pre-iOS 13 way is to observe the operationCount property of the operation queue

var observation : NSKeyValueObservation?

...

observation = operationQueue.observe(\.operationCount, options: [.new]) { observed, change in
        if change.newValue == 0 {
            print("operations finished")
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM