Reputation: 38667
Why is NSURLSession
operation queue empty after creating and resuming an NSURLSessionTask?
Is there a way to tell if an NSURLSession has tasks pending?
The goal is to wait for multiple tasks to complete, but this doesn't work:
NSURLSessionUploadTask *uploadTask = [self.session uploadTaskWithStreamedRequest:request];
[uploadTask resume];
// this prints "0"
NSLog(self.session.delegateQueue.operationCount)
// this returns immediately instead of waiting for task to complete
[self.session.delegateQueue waitUntilAllOperationsAreFinished];
Upvotes: 3
Views: 4561
Reputation: 763
In addition to @Cœur's solution, if you just need to wait for all request responses before continuing code execution you don't need to use a queue. Instead of:
dispatchGroup.notify(queue: .main) {
// here, all the tasks are completed
}
you can simply use:
// Waits that all requests finish.
dispatchGroup.wait()
And continue code execution after this point.
Upvotes: 1
Reputation: 38667
I found a solution that avoids invalidating the session, using the suggested DispatchGroup
.
(answer is in Swift, while question is in ObjC ... but it's the same logic)
Note that when using, uploadTaskWithStreamedRequest:
, we need to implement an URLSessionTaskDelegate
and func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?)
. So, to simplify the answer, I will demonstrate the use of DispatchGroup
with uploadTaskWithRequest:from:completionHandler:
.
// strong reference to the dispatch group
let dispatchGroup = DispatchGroup()
func performManyThings() {
for _ in 1...3 {
let request = URLRequest(url: URL(string: "http://example.com")!)
dispatchGroup.enter()
let uploadTask = self.session.uploadTask(with: request, from: nil) { [weak self] _, _, _ in
self?.dispatchGroup.leave()
}
uploadTask.resume()
}
dispatchGroup.notify(queue: .main) {
// here, all the tasks are completed
}
}
Upvotes: 11
Reputation: 10407
It's very easy as long as you don't care about reusing the session and don't mind doing things asynchronously:
finishTasksAndInvalidate
on the session.URLSession:didBecomeInvalidWithError:
method in your session delegate to do whatever work you need to do after the last task finishes.That said, the problem with your code above is that the session doesn't have any operations until it starts the first fetch, which can't happen as long as your code is blocking the run loop. You generally should not attempt to use NSURLSession synchronously. It is almost always the wrong way to solve things. :-)
Upvotes: 1