Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UIWebView doesn't always call -[NSURLCache storeCachedResponse:forRequest:]

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.

like image 887
aherlambang Avatar asked Jan 27 '12 19:01

aherlambang


People also ask

What is NSURLCache?

The NSURLCache class implements the caching of responses to URL load requests, by mapping NSURLRequest objects to NSCachedURLResponse objects. It provides a composite in-memory and on-disk cache, and lets you manipulate the sizes of both the in-memory and on-disk portions.


4 Answers

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.

like image 63
MrGomez Avatar answered Nov 03 '22 00:11

MrGomez


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

like image 43
Sergey Kuryanov Avatar answered Nov 03 '22 00:11

Sergey Kuryanov


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"];
like image 45
Fabian Aussems Avatar answered Nov 03 '22 00:11

Fabian Aussems


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);
}
like image 43
Daniel Bauke Avatar answered Nov 03 '22 01:11

Daniel Bauke