Reputation: 16430
I have created a simple testing app to learn how to use NSURLSession
. This App has to download images from a webservice and present them into a UITableView
.
I've already written the first part of the App that reads a list of images urls from the web service, now, I want to display this list.
My doubt is:
given that the list of images could be a really long list, is it ok to create a NSURLSessionDownloadTask
for each image?
I thought to create the session in the cellForRowAtIndexPath
function and store the NSURLSessions in a NSDictionary using as key the IndexPath
of the cell (and probably relying on NSURLCache
to avoid to download the same images more than once).
Other solutions:
I can see three more solutions:
Using GCD
with dispatch_async
Subclassing NSOperation and essentially store an NSOperation
for any image I need to download.
Using a third party library like AFNetwork
... but since it is a learning purpose app I prefer to go completely with my code
.
If the multiple NSURLSession isn't a good solution, I'd choose one of those options.
What do you think about this approach?
Upvotes: 2
Views: 1797
Reputation: 10938
I would use (or at least take a look at) SDWebImage's SDWebImageManager
.
Besides downloading you can set priority and continue in the background options which I think you'll want to have.
Upvotes: 1
Reputation: 21254
NSURLSessionTask is fine for a large number of downloads. One advantage of it over some of the other methods you mentioned is that downloads can be cancelled or paused. It also correctly implements concurrency for network operations, which is more difficult than many cats on the internet will lead you to believe (if you don't believe me, view the eskimo's 2010 WWDC session and sample code. NSOperation for network connections is not trivial).
NSURLSessionTask and friends are designed for exactly the kinds of problems you are trying to solve, and it's very well tested.
For a tableview, start the task in tableView:willDisplayCell:forRowAtIndexPath:
and cancel (or pause) a task in tableView:didEndDisplayingCell:forRowAtIndexPath:
. That will limit the active downloads to the currently visible cells.
Upvotes: 6
Reputation: 500
IMO whilst it is ok to create an NSURLSessionTask
for each image a standard first in first out implementation will cause problems when scrolling through your cells. The reason for this is that downloads will be queued on your NSURLSession
and tasks will be executed in the order they've been added to the queue, in other words in a FIFO manner. Imagine a scenario where you've scrolled through a vast number of cells and you have to wait for all downloads to complete in order. You would not only have to wait a long time, you would be making unnecessary network requests for image assets that may no longer be relevant to your user.
Nick Lockwood created a great NSOperationQueue
subclass called NSOperationStack
that reverses the order of operations so that the the last operation is executed first (LIFO). IMO for a large number of downloads a LIFO implementation is a must.
NSOsperationStack
is available here
If you combine this with an implementation that uses cellForRowAtIndexPath
to initiate and NSURLCache
to store downloads, you should end up with a very streamlined and efficient solution.
Upvotes: 1
Reputation: 107231
Suggestion:
I also came across a similar situation were I need to download about 2000 Image files and 100 Video files. For that purpose I implemented a custom download manager using NSOperationQueue
and blocks.
I have added this library to GitHub, please feel free to check the implementation.
Upvotes: 3