1

I have an app that is downloading several photos off of Flickr. Right now, all the photos are downloaded with a custom NSOperation class run on an NSOperationQueue.However, I have heard about NSUrlConnection async being more efficient, and was wondering which is better of this situation? Or, is there a third option that's even better than these two? The custom NSOperation simply calls [NSData dataWithContentsOfURL:] many times on different photos.

charleyh
  • 2,033
  • 2
  • 20
  • 32
  • I've done both. Through-put was comparable and `NSOperation` approach was simpler and more elegant. Having said that it's hard to assess efficiency of your custom `NSOperation` without knowing what it does. Third option is leverage framework like [`AFNetworking`](https://github.com/AFNetworking/AFNetworking). – Rob May 24 '13 at 06:46
  • If we are at recommending third party network libraries, there is AFNetworkKit which is worth to be considered. – CouchDeveloper May 24 '13 at 14:43
  • @CouchDeveloper AFNetworkKit? Did you mean [`MKNetworkKit`](https://github.com/MugunthKumar/MKNetworkKit)? Going to OP's question, I like the fact that `AFNetworking` creates dedicated thread for network operations, rather than what `MKNetworkKit` does, namely adding the network operations to the main queue. In most scenarios, they should be equivalent, but isolation of network thread seems prudent. – Rob May 24 '13 at 15:02
  • I agree with @Rob that AFNetwork seems preferable, as the user will be sitting there for some time during loading and I need to have a MBProgressHUD run on the main thread. – charleyh May 24 '13 at 15:39

3 Answers3

5

Using an approach which utilizes a subclass of NSOperation and which encapsulates NSURLConnection which is used in asynchronous mode (implementing the delegate protocols) is likely the most efficient, iff you additionally consider these aspects:

Ensure that the NSOperation subclass handles the delegate methods quickly, and that the underlaying thread (or the queue) will NOT be used to process the response data. Ideally, the delegate methods pass over the partial response data to another queue or thread where they are processed (note: image data may be preloaded on a background thread or a queue!).

The reason for this is that, the sooner the network operation finishes, the more requests can be performed per time. The network NSOperation shall be put into a NSOperationQueue whose max concurrent operations is set to 1, or 2. Rarely to 4 or higher. This setting depends on whether the server supports pipelining, and on the speed of the connection. Name that queue "Network bound queue".

The "data process" (preload image data) task is ideally a subclass of NSOperation, too. Likewise, the "data process" operations should be queued in a CPU bound NSOperationQueue. Per default the max concurrent operations of a NSOperationQueue is already suitable for CPU bound operations.

If you want to save the data to disk, again, ideally you create a NSOperation and queue those disk operations in a "disk bound queue". On devices, this seems not necessary, but if you have still such oldish "disks" - than it makes sense to set the number of max concurrent operations to the number of independent heads of the disk. ;)

Well, this all may make only a difference, when the connection is really fast and if you are able to process that much data in the same time. We are talking about 5 Mbyte per second on a device, and probably 25 Mbyte per second on a lab top.

CouchDeveloper
  • 18,174
  • 3
  • 45
  • 67
  • 2
    +1 I agree with most of this. I might only quibble re `maxConcurrentOperationCount` which I generally set to 4 or 5, which I find that it offers a huge performance improvement over 1 or 2. Definitely not more than 4 or 5, but using values larger than 1 or 2 can result in substantial performance improvements. – Rob May 24 '13 at 14:37
  • Whoa, have to agree with you hear. I changed it from 1 to 4 and saw a massive performance jump. – charleyh May 24 '13 at 14:53
  • This is what you have to test in a real environment. Generally, if the connection is stable and fast, you see better performance with 2 or more concurrent network operations. When your connections is really fast (LTE) then you might get trouble to process those data, even when you distribute the work on all available CPUs ;) – CouchDeveloper May 24 '13 at 14:58
  • One note to the number of concurrent network operations. Be really careful not to set this number too high. 2 is already quite good if you connect to the same server and then pipelining can be utilized. But beware - don't set it really high! 10.000 connections may cause the server to drop the connections (100 users * 100 concurrent connections), and the bandwidth is also limited. – CouchDeveloper May 24 '13 at 15:04
  • 2
    @CouchDeveloper I agree with constraining it to 4 or 5. It not only makes your app a "good citizen" (i.e. from a server perspective), but in my experience, you can't have more than 5 `NSURLConnection` requests going at the same time, anyway (if more than 5, only 5 will actually operate at the same time, and subsequent requests will freeze and, worse, time-out and fail if not started within 60 seconds). In my experience, 4 or 5 balances performance, responsible citizenry, and `NSURLConnection` constraints. – Rob May 24 '13 at 15:56
  • 1
    I fully agree - and it's good to know that NSURLConnection limits the number of actual opened sockets to a reasonable value. ;) – CouchDeveloper May 24 '13 at 16:05
0

Try these tutorials may help you:

  1. http://maniacdev.com/2010/03/easier-threading-with-nsoperation-for-better-performance

  2. http://www.raywenderlich.com/19788/how-to-use-nsoperations-and-nsoperationqueues

  3. http://www.icodeblog.com/2012/10/19/tutorial-asynchronous-http-client-using-nsoperationqueue/

OR

If you are downloading photos and showing them in table cell, then you can use Lazy loading images.

pankaj asudani
  • 862
  • 6
  • 18
0

I would recommend using AFNetworking (AFNetworking on Github) which has built-in functionality for queuing operations. If you only use it to load images that need to be displayed in a table view cell, you could use the AFNetworking category on UIImageView to load these images asynchronously.

vikingosegundo
  • 52,040
  • 14
  • 137
  • 178
jansenmaarten
  • 1,953
  • 1
  • 11
  • 6