19
votes

I'm looking for a network caching solution for my iOS application that is persistent across launches. I started to read about NSURLCache, but didn't see any mention regarding persistence. Does anyone know how this behaves when you use NSURLCache then close and open the app? Does it persist?

1
To be clearer, whenever you use NSURLConnection, it caches results in memory and on disk according to the cache policy and response cache header. The on disk cache implies persistence across loads and I can personally verify this behavior.Brian Nickel
@Rob if memory serves, NSURLCache behaviour changed in iOS 5, that also being when Apple started differentiating between files the OS may delete at any time, files that should be synchronised via iCloud and files for which neither of those things is true. So could your sources possibly be from the pre-5 world?Tommy
@Tommy Doing a little research, I've found that persistent storage caching is finicky, but works in iOS. I've found that it won't cache to persistent storage if (a) you use the default NSURLRequest cachePolicy of NSURLRequestUseProtocolCachePolicy; but (b) the response doesn't include the Cache-Control header. But if you use a cachePolicy of NSURLRequestReturnCacheDataElseLoad, or if the response from the server specifies a particular Cache-Control header (e.g. public, max-age=1835400), it will cache to persistent storage. Or you can manually add to NSURLCache, too.Rob
Your wording could be confusing. Please correct me if I'm wrong: Generally: Caching and persistence are orthogonal. Caching is to improve performance and may or may not be persisted depending on needs. Persistence is simply “how do I persist any data across an app restart?” Any persistence technique can be used as a backend for persisting “cache" data. Since cache data is just data. The term “cache" just communicates the data’s intended use case. Specifically: here you're talking about persisting the cache through different launches which I believe is correct.Honey

1 Answers

13
votes

NSURLCache automatically caches requests for requests made over NSURLConnection and UIWebViews according to the cache response from the server, the cache configuration, and the request's cache policy. These responses are stored in memory and on disk for the lifetime of the cache.


Aside

I validated the behavior with the following code. You do not need to use any of the below in your own code. This is just to demonstrate how I confirmed the behavior.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // Prime the cache.
    [NSURLCache sharedURLCache];
    sleep(1); // Again, this is for demonstration purposes only. I wouldn't do this in a real app.

    // Choose a long cached URL.
    NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:@"http://cdn.sstatic.net/stackoverflow/img/favicon.ico"]];

    // Check the cache.
    NSCachedURLResponse *cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:request];
    NSLog(cachedResponse ? @"Cached response found!" : @"No cached response found.");

    // Load the file.
    [NSURLConnection sendSynchronousRequest:request returningResponse:NULL error:NULL];

    return YES;
}

The code does the following:

  1. Primes the cache. I noticed a behavior where the cache would not return the cached result until the cache had been initialized and had a chance to scan the disk.
  2. Creates a request for a long-cached file.
  3. Checks if a response exists for the URL and displays the status.
  4. Loads the URL.

On first load, you should see "No cached response found." On subsequent runs, you will see "Cached response found!"