Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I use NSOperationQueue with NSURLSession?

I'm trying to build a bulk image downloader, where images can be added to a queue on the fly to be downloaded, and I can find out the progress and when they're done downloading.

Through my reading it seems like NSOperationQueue for the queue functionality and NSURLSession for the network functionality seems like my best bet, but I'm confused as to how to use the two in tandem.

I know I add instances of NSOperation to the NSOperationQueue and they get queued. And it seems I create a download task with NSURLSessionDownloadTask, and multiple if I need multiple tasks, but I'm not sure how I put the two together.

NSURLSessionDownloadTaskDelegate seems to have all the information I need for download progress and completion notifications, but I also need to be able to stop a specific download, stop all the downloads, and deal with the data I get back from the download.

like image 934
Doug Smith Avatar asked Feb 20 '14 20:02

Doug Smith


People also ask

What is the difference between NSOperationQueue and GCD?

GCD is a low-level C-based API that enables very simple use of a task-based concurrency model. NSOperation and NSOperationQueue are Objective-C classes that do a similar thing. NSOperation was introduced first, but as of 10.5 and iOS 2, NSOperationQueue and friends are internally implemented using GCD .

What is NSOperationQueue?

A queue that regulates the execution of operations.


1 Answers

Your intuition here is correct. If issuing many requests, having an NSOperationQueue with maxConcurrentOperationCount of 4 or 5 can be very useful. In the absence of that, if you issue many requests (say, 50 large images), you can suffer timeout problems when working on a slow network connection (e.g. some cellular connections). Operation queues have other advantages, too (e.g. dependencies, assigning priorities, etc.), but controlling the degree of concurrency is the key benefit, IMHO.

If you are using completionHandler based requests, implementing operation-based solution is pretty trivial (it's the typical concurrent NSOperation subclass implementation; see the Configuring Operations for Concurrent Execution section of the Operation Queues chapter of the Concurrency Programming Guide for more information).

If you are using the delegate based implementation, things start to get pretty hairy pretty quickly, though. This is because of an understandable (but incredibly annoying) feature of NSURLSession whereby the task-level delegates are implemented at the session-level. (Think about that: Two different requests that require different handling are calling the same delegate method on the shared session object. Egad!)

Wrapping a delegate-based NSURLSessionTask in an operation can be done (I, and others I'm sure, have done it), but it involves an unwieldy process of having the session object maintain a dictionary cross referencing task identifiers with task operation objects, have it pass these task delegate methods passed to the task object, and then have the task objects conform to the various NSURLSessionTask delegate protocols. It's a pretty significant amount of work required because NSURLSession doesn't provide a maxConcurrentOperationCount-style feature on the session (to say nothing of other NSOperationQueue goodness, like dependencies, completion blocks, etc.).

And it's worth pointing out that operation-based implementation is a bit of a non-starter with background sessions, though. Your upload/download tasks will continue to operate well after the app has been terminated (which is a good thing, that's fairly essential behavior in a background request), but when your app is restarted, the operation queue and all of its operations are gone. So you have to use a pure delegate-based NSURLSession implementation for background sessions.

like image 56
Rob Avatar answered Sep 21 '22 21:09

Rob