3

There are many third parties libraries for loading a network image and then store it into a disk and/or memory.

However it is very easy to implement it using simple NSURLSession API call.

here is the code:

     NSURLCache *myCache = [[NSURLCache alloc] initWithMemoryCapacity: 16384 diskCapacity: 268435456 diskPath: cachePath]; // these numbers are only for the usage example.
     defaultConfigObject.URLCache = myCache;
     defaultConfigObject.requestCachePolicy = NSURLRequestUseProtocolCachePolicy;
     _session = [NSURLSession sessionWithConfiguration: defaultConfigObject delegate:self delegateQueue: [NSOperationQueue mainQueue]];

     _dataTask = [_session dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error){

        if (!error){
            UIImage* theImage = [UIImage imageWithData:data];
            dispatch_async(dispatch_get_main_queue(), ^{
                self.image = theImage;

            });
        }
    }];
    [_dataTask resume];

This code downloads an image(from a given url) and store it to memory+disk according to the http caching policy.

Deriving MyNetworkImageView from UIImageView and adding the above code to a setURL: method, is also straight forward.

My question is:

What are the advantages of using other third parties frameworks such as AFNetworking,FastImageCache,SDWebImage,SDImageCache?

Amir Aharon
  • 291
  • 2
  • 9
  • Caching in `NSURLSession` is contingent upon (a) size of download relative to size of cache; and (b) the headers of the response. I'd really stress test your app and make sure the caching (esp persistent storage cache) is working like you think it is. Your memory cache seems is really small (and anything exceeding 5% of cache size won't get cached). Bottom line, relying upon `NSURLCache` in iOS has been problematic in the past, especially if you don't control the server. These classes offer other advantages, too (e.g. with `UIImageView` categories). – Rob Jul 12 '15 at 14:46
  • Thanks Rob. I've edit my question per your remarks. regarding the memory cache size, it's only for the usage example, there are not real work numbers. regarding NSURLCache problematic in iOS, I recall such issues but I believe they are no longer relevant in iOS8 and above. finally, assuming the server defines the caching behaviour, are there more advantages? – Amir Aharon Jul 12 '15 at 15:09
  • OK. I'd generally expect the memory cache to be in MB, not KB. :) Re success of cacheing by `NSURLCache`, I'd only suggest empirically verifying this, first. But if `NSURLSession` works for your needs, then go ahead and just use that. I'd step back and think about the broader networking needs of the app, but if you don't need complex HTTP request creation/processing, nor `UIImageView` categories, etc., then just stick with `NSURLSession`. – Rob Jul 12 '15 at 15:23

2 Answers2

1
  1. Caching in these frameworks is more deterministic. The NSURLCache used by NSURLSession is (a) somewhat opaque (e.g. I've never seen the 5% threshold documented); and (b) controlled by the response headers provided by your server.

  2. Before you simply declare NSURLCache "good enough", I would suggest rigorously testing the app and make sure the caching (esp persistent storage cache: run the app, download images; terminate (not just suspend) the app; re-run the app) is working like you hope it is. Make sure to test both runtime cacheing as well as persistent storage cacheing.

  3. As an aside, your memory cache seems is really small (and anything exceeding 5% of cache size won't get cached). It's a matter of opinion, but I'd generally expect to see something closer to 16mb rather than 16kb. As it is, this won't cache anything exceeding 800 bytes or so!

  4. These frameworks offer many other advantages, too.

    • The UIImageView categories provided by AFNetworking and SDWebImage are the easiest way to achieve asynchronous image retrieval. In particular, when cells are reused in table/collection view, it will cancel the prior requests, making sure that the image requests for visible cells are prioritized. (You don't want to quickly scroll to 100th row in table and have to wait for 99 no-long-visible images to download before you start downloading the images for the visible cells.)

    • If generating complex HTTP requests, AFNetworking lets you focus on the app logic rather than writing and testing complex networking code.

Bottom line, relying upon NSURLCache in iOS has been problematic in the past, especially if you don't control the server. These classes offer other advantages, too (e.g. with UIImageView categories).

Rob
  • 415,655
  • 72
  • 787
  • 1,044
  • Correct me if I'm wrong but AFNetworking also uses NSURLCache (and by default doesn't cache to disk): https://github.com/AFNetworking/AFNetworking/wiki/AFNetworking-FAQ – Amir Aharon Jul 13 '15 at 04:53
  • @user2955669 - AFNetworking's `UIImageView` category also uses its own manual `NSCache`. But, yes, underneath it also enjoys `NSURLCache` functionality, too. But you can cache to disk via `NSURLCache` (e.g. subject to all of the constraints and limitations `NSURLCache` entails). `SDWebImage` does its own persistent storage caching, last time I used it. – Rob Jul 13 '15 at 04:56
  • Also notice that "NSURLConnection is deprecated in iOS9" (https://developer.apple.com/videos/wwdc/2015/?id=711), will still work but eventually will end. AFNetworking still uses NSURLConnection but will have to be modified to work only on top of NSURLSession, so AFNetworking API benefits (such as block based API) comparing to NSURLConnection API, will also deprecate. – Amir Aharon Jul 13 '15 at 05:26
  • Agreed. So, if you don't need backward compatibility with older OS versions, and if you're OK with `NSURLCache` limitations, then doing something in `NSURLSession` is good idea. But you'll need something far richer than you've contemplated in your question above because caching is only one of many considerations, e.g. prioritizing visible images so when you scroll quickly through images w slow network connection that it doesn't get backlogged, constraining degree of concurrency, prefetching/preheating, etc.). – Rob Jul 15 '15 at 03:11
0

NSURLCache is a great tool, especially when you need revalidation mechanisms, and NSURLCache handles HTTP revalidation transparently for you. NSURLSession is also a good step forward for Cocoa networking.

However, it's not that easy to implement image fetching in an efficient way. There are some special requirements that you might have in you app:

  1. Avoid image decompression on the main thread, which is costly, especially for jpg.
  2. Have a separate in-memory cache layer on top of NSURLCache to store decompressed images, and be able to retrieve them synchronously on the main thread. Managing in-memory cache it not that simple either, even if you use NSCache.
  3. Have some abstraction on top on networking layer in order to be able to add support for more image formats when necessary, like gif or webp. And extend image fetching in other ways.
  4. Group same image requests and not create excessive session tasks
  5. Be able to preheat images efficiently
  6. Have a way to fetch low-resolution placeholder first and then wait for the high-resolution image

And more.

AFNetworking,FastImageCache,SDWebImage,SDImageCache

Neither of those frameworks use NSURLSession (some even have their own disk cache implementations), please check out Nuke / DFImageManager instead. It's built on top of NSURLSession, it has all the above features, and it also has multiple subspecs that integrate things like AFNetworking* as a networking stack, and FLAnimatedImage as an animated GIF engine, and more.

*AFNetworking is based on NSRULSession, but their image fetching implementation is still based on top of NSURLConnection (AFHTTPRequestOperation).

kelin
  • 11,323
  • 6
  • 67
  • 104
kean
  • 1,561
  • 14
  • 22