9

It seems that UIWebView doesn't always call storeCachedResponse:forRequest: whenever it's loading a resource. Does anyone know why? I am trying to cache images by using -[NSURLCache storeCachedResponse:forRequest:], it does most of the job fine, however in some cases UIWebView doesn't call this method on page load where there are actually images on it.

Costique
  • 23,712
  • 4
  • 76
  • 79
aherlambang
  • 14,290
  • 50
  • 150
  • 253
  • I notice this too; though only *on* device for my app. When the web view loads a request from the NSURLCache, it seems to skip over that very same cache for assets on that page. – Nevir Mar 28 '12 at 01:05

5 Answers5

11

Answering the bounty provider's query:

I'm seeing this for small files (100s of bytes) as well. The webview also fails to call cachedResponseForRequest:

I found this question that addresses this behavior directly:

Despite Apple's documentation indicating otherwise, NSURLCache on iOS doesn't do any disk (flash) caching at all. You can subclass NSURLCache to change the behaviour of the fetch and store operations to use the disk (like SDURLCache does), but due to the following severe limitations of how the cache is used and implemented, this doesn't work as well as you'd expect:

  • NSURLConnection doesn't even call storeCachedResponse:forRequest: for files over about 50KB (>= 52428 bytes, to be exact). This makes subclassing NSURLCache pointless for our use (200KB images), because it won't even get to the cache. As a result, we have to add caching manually at a level above NSURLConnection.

  • Even when one calls the NSURLCache's built-in storeCachedResponse:forRequest: manually, it only stores the response in memory if it's less than about 180KB. I tested this by calling storeCachedResponse manually and seeing that the before/after currentMemoryUsage didn't change for data lengths above about 180KB. So we have to write our own LRU memory caching too.

(Emphasis mine.)

This seems to be responsible for the behavior being called out. As the current accepted answer points out, ASIHTTPRequest is the expected workaround for this behavior.

However, note the caveat at the top of the page:

Please note that I am no longer working on this library - you may want to consider using something else for new projects. :)

You should consider relying on supported libraries or, if you prefer, contributing back to this library once it underlies your code.

Community
  • 1
  • 1
MrGomez
  • 23,788
  • 45
  • 72
  • 1
    Appreciate it :) (And a great example of where I should have searched harder) - thanks for taking the time to thoroughly dig into this! – Nevir Apr 02 '12 at 00:56
  • @Nevir No problem! I'm happy it was useful. :) – MrGomez Apr 02 '12 at 01:33
  • Does anyone know if this is still the case with NSURLSession on iOS 7/8? I'm having problems getting NSURLCache to save large (~7MB) image files. – Andrew Ebling Nov 20 '14 at 14:36
4

As described here NSURLConnection doesn't call storeCachedResponse:forRequest: if file size over 50kb(52428 bytes).
Try ASIHTTPRequest caching.

Community
  • 1
  • 1
Sergey Kuryanov
  • 6,114
  • 30
  • 52
  • I'm seeing this for small files (100s of bytes) as well. The webview also fails to call `cachedResponseForRequest:` – Nevir Mar 29 '12 at 21:40
3

NSURLCache works with two different caches: on-disk cache and in-memory cache

  • Responses will be cached to in-memory cache if the response size is under 50kb and
  • Responses will be cached to on-disk cache if the response size is over 50kb

If you initialize NSURLCache with diskPath nil then the on-disk cache will not be active and storeCachedResponse:forRequest: will only be called for response sizes that are under 50kb.

So configure your URLCache like this

[[MYCustomURLCache alloc] initWithMemoryCapacity:4 * 1024 * 1024 
                          diskCapacity:20 * 1024 * 1024 
                          diskPath:@"urlcache.db"];
2

I'm not sure how it works for a UIWebvieuw, but when you use a NSURLRequest the maximum size of the file depends on how you initialize the URLCache (initWithMemoryCapacity:(NSUInteger)memoryCapacity ...) I just cached a 2MB file

Edwin Vermeer
  • 13,017
  • 2
  • 34
  • 58
  • For me, a 515KB .css file requested from UIWebView can be treated with `cachedResponseForRequest:` of a `NSURLCache` subclass initialized with `memoryCapacity:0 diskCapacity:1024*1024*256` – hiroshi Aug 11 '14 at 02:52
2

Have you checked HTTP status and cache headers? Expires, Cache-Control etc? Maybe a server answers with status=304 without any response body?

- (void)connection:(NSURLConnection *)conn didReceiveResponse:(NSURLResponse *)aResponse 
{
  NSLog(@"CODE: %d", ((NSHTTPURLResponse *)aResponse).statusCode);
  NSLog(@"HEADERS: %@", ((NSHTTPURLResponse *)aResponse).allHeaderFields);
}
Daniel Bauke
  • 1,208
  • 14
  • 25