I am downloading WMS tiles which I want to cache. I'm using AFNetworking which includes NSURLCache. The responses from the server do not contain Cache-Control protocols in the header.
I asked the server guy about this and was unfamiliar with server side cache-control. At the moment, he is swamped with other work. Do I need him to implement the cache-control or can I force NSURLCache to cache them w/out the info the response header?
Is NSURLCache persistent? If so, how can I clear the cache? The tiles will need to be retrieved per session and can not be persistent.
Or should I create my own cache?
When you activate NSURLCache it will work for any request that is based on the NSUrlRequest (like AFNetworking). The moment you activate the NSURLCache you can specify it's maximum size. You can also clear the cache by calling the removeAllCachedResponses or removeCachedResponsesForRequest methods. If the server does not send any cache control information, then the cache will still cache the file. If you want complete control over the cache, you could create your own cache. If you would like to see a sample code for that, then have a look at https://github.com/evermeer/EVURLCache
Related
Hi i have read about cache policy but still not quite clear. My purpose is to set request cache 3 minutes. Response cache 3 minutes. keep old cache for 1 day. What is the implementation that we should we use? Is there any setting that we can change beside those default bellow? (I use AFNetworking 3 for request and response). Any help is much appreciate. Thanks
NSURLRequestCachePolicy
NSURLRequest has a cachePolicy property, which specifies the caching behavior of the request according to the following constants:
NSURLRequestUseProtocolCachePolicy: Caching logic defined in the protocol implementation is used for a particular URL load request. This is the default policy.
NSURLRequestReloadIgnoringLocalCacheData: Data should be loaded from the originating source. No existing cache data should be used.
NSURLRequestReloadIgnoringLocalAndRemoteCacheData: Not only should the local cache data be ignored, but proxies and other intermediates should be instructed to disregard their caches so far as the protocol allows.
NSURLRequestReturnCacheDataElseLoad: Existing cached data should be used, regardless of its age or expiration date. If there is no existing data in the cache corresponding to the request, the data is loaded from the originating source.
NSURLRequestReturnCacheDataDontLoad: Existing cache data should be used, regardless of its age or expiration date. If there is no existing data in the cache corresponding to the request, no attempt is made to load the data from the originating source, and the load is considered to have failed, (i.e. “offline” mode).
NSURLRequestReloadRevalidatingCacheData: Existing cache data may be used provided the origin source confirms its validity, otherwise the URL is loaded from the origin source.
You should almost invariably use NSURLRequestUseProtocolCachePolicy unless you're trying to kill caching entirely for some reason.
The cache durations should be set by the server as part of its response (in the Cache-Control header). The iOS URL cache obeys the policies specified in that header.
I am using Alamofire Framework for HTTP requests in my app. Even though by standard URLCaching is not ON, Alamofire sets it as default.
Caching
Caching is handled on the system framework level by NSURLCache.
https://github.com/Alamofire/Alamofire#caching
I understand that caching is important for performance (network, CPU etc.) but if caching is not expiring after some minutes, caching prevents the app from checking whether if the remote content has changed or not.
I also have read a lot of articles explaining how efficient method caching is and how recommended for use.
Then my question is, when will the cached data expire? Will it ever expire?
The cache will expire based on the 'Cache-Control' HTTP-Header contained within the response to the request.
NSURLSession uses NSURLCache for this, and since Alamofire uses NSURLSession under the hood, the Cache-Control header is what determines the expiry time.
I am using SDWebImage library to download images from server.
https://github.com/rs/SDWebImage
SDWebImage not able update the cached image when image updated on server with the same url.
SDWebImage does some caching by default, so it would be better to use a new URL if the image changes. So, for instance, if you have control over the URL and can change it every time the image has changed, you could do that.
If that's not the case, try using SDWebImageRefreshCached in the options field in order to respect HTTP cache control headers, like this:
[imageView setImageWithURL:[NSURL URLWithString:#"https://graph.facebook.com/olivier.poitrey/picture"]
placeholderImage:[UIImage imageNamed:#"avatar-placeholder.png"]
options:SDWebImageRefreshCached];
See more here
Update: I've actually written an entire guide about cache, including cache validation https://kean.github.io/blog/image-caching
SDWebImage uses NSURLCache when you set SDWebImageRefreshCached option. Apple's URL loading system implements HTTP cache, including cached responses validation. HTTP cache is quite complex, however there are many beginners guides on HTTP caching:
How To Optimize Your Site With HTTP
Caching
HTTP caching
Basically, the server needs to include some of HTTP cache control headers in each response. There are many different strategies that can be used to implement revalidation. You may use either Last-Modified or ETag. This way each time the client sends a request it will automatically include in your request either Last-Modified or ETag value from previously cached response. If the image hasn't change the server will respond with status code 302 (not modified) and NSURLConnection/NSURLSession will transparently give you a cached response from NSURLCache. You don't have to download the data again, buy you still need to check with the server each time you make a request.
You can also specify an expiration date using HTTP cache control. If the expiration mechanism is used, NSURLConnection/NSURLSession will not revalidate cached response until it is not expired.
For more info about HTTP cache control see the links above. HTTP cache is a universal cache mechanism that should be used whenever possible.
I would recommend to use Nuke framework for image loading (disclaimer: writted by me). It uses NSURLCache by default while still having a memory cache that holds decompressed images.
Here is a code in swift 3 to refresh cache everytime
imgCardBack.sd_setImage(with: URL(string: objUserData.back_image!), placeholderImage:UIImage(named: "cardBack"), options: .refreshCached)
Swift 4
Simply use the following function in the SDWebImage Library :
SDImageCache.shared().removeImage(forKey: (ImagePath), withCompletion: nil)
This function will delete the saved Cash in memory and Disk , after that just Upload your new Image at the same and it will work perfectly.
Go to the line number 176 in the file SDWebImageManager.m and change this line
if (options & SDWebImageRefreshCached) downloaderOptions |= SDWebImageDownloaderUseNSURLCache;
to below code.
if (options & SDWebImageRefreshCached) {
// force progressive off if image already cached but forced refreshing
downloaderOptions &= ~SDWebImageDownloaderProgressiveDownload;
// remove SDWebImageDownloaderUseNSURLCache flag
downloaderOptions &= ~SDWebImageDownloaderUseNSURLCache;
//ignore image read from NSURLCache if image is cached but force refreshing
downloaderOptions |= SDWebImageDownloaderIgnoreCachedResponse;
}
For me it worked like a charm.
If URL is not changed there is now way for SDWebImage to know that image has been changed on the server.
I am using NSUrlConnection to grab some data from a web service that returns JSON data when I hit a url but sometimes the page goes down or something is wrong.
Is there a way to use the cached version of the url in my iOS App to grab that data when the webpage returns a 404?
In the browser if I go to cache:mysite.com/test.php I can see the JSON data even when the page is down but when I try to use the same url in my iOS App, I do not get the JSON data back.
Is there maybe an Obj C class I am not aware of or an option for the NSUrlConnection?
NSURLConnection already uses a cache. By default it only caches responses in-memory, you can customize this by setting it to also use on-disk storage:
NSURLCache *result = [[NSURLCache alloc] initWithMemoryCapacity:[(1024*1024*512) diskCapacity:(1024*1024*1024 * 100) diskPath#"Cache.db"]:
[NSURLCache setSharedURLCache:result];
The reason you are seeing the behavior you describe in your question is that the remote web service is telling your client not to cache the response. You can check this using REDbot or a tool like Charles. By default NSURLRequest will use the protocol's caching policy and semantics, which is almost always the correct thing to do. You can specify a different cache policy by changing the cachePolicy property of the NSURLRequest.
After much search, I didn't find a way to get a cached version of a web page in my iOS app but I handled the 404 error by looking for the response status code and using a service like Google Cache or archive.org/web/ to get the cached version of the url if a 404 was found.
Might not be the most delicate way but I could not find another way to get a cached version of the website when making the request.
If I download a document using NSURLConnection/NSURLCache that gets cached, edit that document on the server (so Last-Modified and Etag headers change) and then download the document again, the previously cache version is returned. NSURLCache/NSURLConnection makes no attempt to check for a newer resource using If-Modified-Since/If-None-Match headers in the request (which would return a newer version of the resource).
SHould NSURLCache used in conjunction with NSURLConnection check for an updated resource on the server using Last-Modified/Etag headers that have been previously cached? I can't seem to find any documentation to say whether this should happen or if checking for HTTP 304 content is up to the developer.
I'll let other people comment on how to use NSURLCache. I found that the most reliable way to prevent caching with NSURLConnection, proxy servers, and misconfigured web servers, was to append an incrementing number to your URL.
So rather than using http://mycompany.com/path, use http://mycompany.com/path?c=1, http://mycompany.com/path?c=2, http://mycompany.com/path?c=3, etc, etc.
It's a hack, but a good one.