I have a UITableView whose cells contain custom ImageViews that asynchronously load the images from the internet. To load those images I use NSURLRequest and NSURLConnection which works fine. The only problem is that the images are not cached and therefore are downloaded every time they are used. I tried to set the cachePolicy of the NSURLRequest to "NSURLRequestReturnCacheDataElseLoad" with no effect.
It seems from the last answer on link that disk caching is not supported with NSURLRequest on the iPhone. Is this correct?
If it should actually work, I'd be interested to know what could be the reason that it doesn't work in my case.
Here's the code:
NSURLRequest* request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://myurl"] cachePolicy:NSURLRequestReturnCacheDataElseLoad timeoutInterval:60.0];
connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
I think it should work. If it does not then it could mean that the web server is actually serving content that is not cacheable. For example because it is not setting the right headers.
If you can post a link to one of the images then we can take a close look.
HTTP/1.1 200 OK
Date: Mon, 01 Mar 2010 12:40:46 GMT
Server: Apache
Last-Modified: Mon, 01 Mar 2010 09:33:29 GMT
ETag: "25e8dd2-11a6-480b9f1178c40"
Accept-Ranges: bytes
Content-Length: 4518
Keep-Alive: timeout=15, max=100
Connection: Keep-Alive
Content-Type: image/png
This is what one of your images returns as headers. I don't see a Expires
or Cache-Control
header, so that may be why they are not cached. I think as far as WebKit is concerned, this is dynamic content that should be reloaded every time.
NSURLCache
on-disk caching has worked since iOS 5. By default NSURLCache
does not use on-disk caching, you must enable it yourself:
NSURLCache *cache = [[NSURLCache alloc] initWithMemoryCapacity:(1024*1024*512) diskCapacity:(1024*1024*1024 * 100) diskPath@"Cache.db"];
[NSURLCache setSharedURLCache:cache];
This will set the global URL cache to be used for the URL loading system. For the most part, this will "just work". If your request uses NSURLRequestUseProtocolCachePolicy
, which is the default, the URL loading system will cache with the lifetimes indicated by the remote server response. Services such as REDbot can tell you what the cache lifetime of a given response would be.
NSURLSessionConfiguration
can be configured to use separate caches, however in practice this does not work as documented. As of iOS 8, if multiple NSURLCache
s are configured only the first will actually be used.
There are additional undocumented behaviors when using on disk storage with NSURLCache
:
- If the diskCapacity
is set to less than 5MB, it will not be used.
- Purging and resizing the cache often does not work as expected. Some of this was fixed in iOS 8, some was not.
- currentDiskUsage
information is often incorrect.
- On some iOS releases NSURLCache
ignores the limit set by diskCapacity
and grows the on-disk cache without limits.
That said, NSURLCache
on disk caching does generally do the right thing. If you create an on-disk cache as above when your application starts up the cache will persist responses to the disk and the URL loading system will use those cached responses. Once you have set the cache as above, you do not need to interact with the cache directly - the URL loading system does that for you. The exception is NSURLSession
, where caching still seems to be a bit broken.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With