Here is the sample function I call when i need to clear cache and make a new call to URL
- (void)clearDataFromNSURLCache:(NSString *)urlString
{
NSURL *requestUrl = [NSURL URLWithString:urlString];
NSURLRequest *dataUrlRequest = [NSURLRequest requestWithURL: requestUrl];
NSURLCache * cache =[NSURLCache sharedURLCache];
NSCachedURLResponse* cacheResponse =[cache cachedResponseForRequest:dataUrlRequest];
if (cacheResponse) {
NSString* dataStr = [NSString stringWithUTF8String:[[cacheResponse data] bytes]];
NSLog(#"data str r= %#",dataStr);
NSLog(#"url str r= %#",[[[cacheResponse response] URL] absoluteString]);
[cache storeCachedResponse:nil forRequest:dataUrlRequest];
[NSURLCache setSharedURLCache:cache];
}
[[NSURLCache sharedURLCache] removeCachedResponseForRequest:dataUrlRequest];
//Check if the response data has been removed/deleted from cache
NSURLRequest *finalRequestUrlRequest = [NSURLRequest requestWithURL:requestUrl];
NSURLCache * finalCache =[NSURLCache sharedURLCache];
NSCachedURLResponse* finalcacheResponse =[finalCache cachedResponseForRequest:finalRequestUrlRequest];
if (finalcacheResponse) {
//Should not enter here
NSString* finaldataStr = [NSString stringWithUTF8String:[[finalcacheResponse data] bytes]];
NSLog(#"data str r= %#",finaldataStr);
NSLog(#"url str r= %#",[[[cacheResponse response] URL] absoluteString]);
}
}
In iOS 6/7 the response is deleted successfully for the requestURL, but in iOS 8 it never gets deleted.
I have searched but could not find any reason why this should not work in iOS8.
Any help will be appreciated…..
NSURLCache is broken on iOS 8.0.x - it never purges the cache at all, so it grows without limit. See http://blog.airsource.co.uk/2014/10/11/nsurlcache-ios8-broken/ for a detailed investigation. Cache purging is fixed in the 8.1 betas - but removeCachedResponseForRequest: is not.
removeCachedResponsesSinceDate: does appear to work on iOS 8.0 - an API that was added for 8.0, but hasn't made it to the docs yet (it is in the API diffs). I am unclear what use it is to anyone - surely what you normally want to do is remove cached responses before a particular date.
removeAllCachedResponses works as well - but that's a real sledgehammer solution.
I got a sufficient result reseting the cached response for a specific URL, changing the cache control to something that would never be returned like a "max-age=0" in the header. Look here
Whenever any API call is generated, That response is saved in the cache. You are able to find that folder in your documents directory, a folder with named cachedb is created which contains a list of responses. It can be a major concern related to security. With any third-party tool, someone can have access to that information.
Below is the way I have solved this issue :
NSURLCache *cache = [[NSURLCache alloc] initWithMemoryCapacity:0 * 1024 * 1024 diskCapacity:0 * 1024 * 1024 diskPath:nil];
[NSURLCache setSharedURLCache:cache];
I have allocated 0 memory space to the cache. so no data will be stored in Cache memory.
Related
in my iOS app I'm the UIImageView category provided by AFNetworking in order to download images stored on Amazon S3. I thought that the default cache stored cached images on disk by default, however, for a number of reasons (missing HTTP headers, etc.) I realized I was mistaken. Images don't seem to be cached, they are downloaded at every execution.
Therefore I'm now trying a custom cache, as suggested here http://blog.originate.com/blog/2014/02/20/afimagecache-vs-nsurlcache/
Here's what I've done so far (which seems to work):
1) defined a custom NSURLCache called PlayerImageCache and initialized it in my app delegate in order to use 5MB of memory and up to 100MB of disk space
PlayerImageCache *sharedCache = [[PlayerImageCache alloc] initWithMemoryCapacity:5*1024*1024 diskCapacity:100*1024*1024 diskPath:nil];
[NSURLCache setSharedURLCache:sharedCache];
2) overrided the storeCachedResponse method in order to always cache my images
- (void)storeCachedResponse:(NSCachedURLResponse *)cachedResponse
forRequest:(NSURLRequest *)request
{
if ([request.URL.absoluteString hasPrefix:playersImagesPrefix])
{
NSCachedURLResponse *modifiedCachedResponse = [[NSCachedURLResponse alloc] initWithResponse:cachedResponse.response data:cachedResponse.data userInfo:cachedResponse.userInfo storagePolicy:NSURLCacheStorageAllowed];
[super storeCachedResponse:modifiedCachedResponse forRequest:request];
}
else
{
[super storeCachedResponse:cachedResponse forRequest:request];
}
}
3) forced every request to check the cache before downloading the image by using the NSURLRequestReturnCacheDataElseLoad policy
NSURLRequest *imageRequest = [NSURLRequest requestWithURL:[NSURL urlForPlayer:self.playerId] cachePolicy:NSURLRequestReturnCacheDataElseLoad timeoutInterval:60];
[self.playerImage setImageWithURLRequest:imageRequest placeholderImage:[UIImage imageNamed:#"playerprofile"] success:nil failure:nil];
Will this be enough? Do I need to further customize my cache? Will this work even without the Cache-Control HTTP header?
The answer is yes! It works like a charm. I managed to greatly decrease the number of requests thanks to this trick.
I am building an app in which I am implementing offline mode as well. For this I used NSURLCache mechanism. When the app is in foreground then the cache mechanism works perfectly even if the device goes in offline mode. The problem comes when I quit the app and then open it in offline mode. This time NSCachedURLResponse is returning nil for the particular request.
Below is the code I am using for this:
Custom Cache Creation:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSURLCache *urlCache = [[NSURLCache alloc] initWithMemoryCapacity:1024*1024 diskCapacity:1024*1024*5 diskPath:nil];
[NSURLCache setSharedURLCache:urlCache];
}
Calling server and cached object:
-(void)serverCall
{
NSURLCache *urlCache = [NSURLCache sharedURLCache];
NSString *urlString = nil;
NSHTTPURLResponse *response = nil;
NSError *error = nil;
urlString = [NSString stringWithFormat:#"%#%#",BASE_URL,url];
urlString = [urlString stringByReplacingOccurrencesOfString:#" " withString:#"%20"];
NSURL *finalUrl = [NSURL URLWithString:urlString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:finalUrl];
request.cachePolicy = NSURLRequestReturnCacheDataElseLoad;
NSData *data = nil;
if ([self checkInternetConnection])
{
data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSCachedURLResponse *cachedResponse = [[NSCachedURLResponse alloc] initWithResponse:response data:data];
[urlCache storeCachedResponse:cachedResponse forRequest:request];
}
else
{
NSCachedURLResponse *cachedResponse = [urlCache cachedResponseForRequest:request];
response = cachedResponse.response;
data = cachedResponse.data;
}
}
I can see that caches.db in library path of application the response is saved. But when i am trying to read it in Offline mode (after app is killed from background), the cached response is coming nil. I have gone through following links (and many more) but couldn't find the solution of my problem.
NSURLCache Problem with cache response
How to use NSURLCache to return cached API responses when offline (iOS App)
http://twobitlabs.com/2012/01/ios-ipad-iphone-nsurlcache-uiwebview-memory-utilization/
http://petersteinberger.com/blog/2012/nsurlcache-uses-a-disk-cache-as-of-ios5/
Bypassing http response header Cache-Control: how to set cache expiration?
I have checked the http header fields and cached header in the api response and the problem is not from server end.
I have also tried providing a path in diskPath param while creating the custom cache but then it doesn't even load the cached object while the app is in foreground and internet disconnects. I have also changed the expiration date but the working is still same.
I have tried using SDURLCache but I am facing the similar problem. However I have successfully achieved this with ASIHTTPRequest but I don't want to use it as I have written all the server operations once already and I have to change every request with ASIHTTPRequest method.
Please help me find a solution for this.
Thanks in advance....
I've got this weird issue with my apps that uses internet connection. The app doesn't seem to update the data from internet in the right way. I've got a UIWebView with a simple chat. When I write a message in the chat with safari or in my web browser everything works fine. When writing something in the chat in the app, the data doesn't update, even when reloading the page.
It updates totally un-logically as well. Even when restarting the app the new data isn't shown, then all of a sudden it shows.
Had the same issue with another app too, which was not handled by a UIWebView. Any idea what it might be?
Example code:
- (void) viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
NSString *username = [[Database singletonDataBase] currentUserName];
NSString *urlAddress = [NSString stringWithFormat:#"%#?name=%#", #"http://webapi.com/index.php", username];
NSURL *url = [NSURL URLWithString:urlAddress];
NSURLRequest *requestObj = [NSURLRequest requestWithURL:url];
[self.webView loadRequest:requestObj];
}
In your app delegates, didFinishLoading method, set the NSURLCache to not cache the data:
// Remove and disable all URL Cache, but doesn't seem to affect the memory
[[NSURLCache sharedURLCache] removeAllCachedResponses];
[[NSURLCache sharedURLCache] setDiskCapacity:0];
[[NSURLCache sharedURLCache] setMemoryCapacity:0];
If that doesn't work, you can also try setting the cache policy on the NSURLRequest:
NSURL *url = [NSURL URLWithString:urlAddress];
NSURLRequest *requestObj = [NSURLRequest requestWithURL:url
cachePolicy:NSURLRequestReloadIgnoringCacheData
timeoutInterval: 10.0];
I finally found the answer. Its nothing wrong with my code, as I thought. The problem lies on the server side. And, as they say in this thread:
NSURLConnection is returning old data
It seems to be badly configured server-side or proxy. Which makes the cache act all wierd. I tried another server and everything worked just fine!
Hope this helps someone with the same issue, cause it sure wasted me ALOT of time.
In my app I load some static JSON string from some server.
Every now and then the JSON file is updated and then I want the app to reload the data.
Now, that I updated the file on the server the app does not reflect the change. If I take the URL to that file from the app's code and copy it into a browser and fetch the file there, I clearly see the updates. But when I run the app and log the json string to the debug console, then I clearly see an outdated version of the file's content.
Is there any caching involved? Can I force the iOS to actually reload it?
This is how I load it now:
NSURL * url = [NSURL URLWithString:[DOWNLOAD_URL stringByAppendingString:DOWNLOAD_FILE]];
NSError * error;
NSData *jsonData = [NSData dataWithContentsOfURL:url options:NSDataReadingUncached error:&error];
NSLog(#"JSON: %#", [NSString stringWithUTF8String:[jsonData bytes]]);
The option NSDataReadingUncached should prevent the system from caching the data.
PS: When I run the app on a different device, then it receives the current data. But when I again let it run on the original device - on which I observe this behaviour - then the data "received" is still outdated. So it really looks like some cashing issue to me.
Here is an idea. Try calling
[[NSURLCache sharedURLCache] removeAllCachedResponses];
For more granular control on cashing use NSURLConnection or NSURLSession.
I did try Mundi's suggestion, to try clearing the cache, but this didn't make any difference in my iPhone app.
So, I tried a trick which I use in my Angular webapps, and appended the current time (in ticks) to the URL I'm attempting to open, and that did work:
NSString* originalURL = #"http://somewebservices/data/1234";
NSString* newURL = [NSString stringWithFormat:#"%#?t=%f", originalURL,
[[NSDate date] timeIntervalSince1970]];
NSLog(#"Loading data from: '%#'", newURL);
NSURL *url = [NSURL URLWithString:newURL];
if (url == nil)
return false;
NSError *error;
NSData* urlData = [NSData dataWithContentsOfURL:url options:NSDataReadingUncached error:&error];
(Sigh.)
I'm getting too old for this stuff....
I am attempting to use NSURLCache so that my app will save JSON responses from a web server and not request it so much.
I have added Cache-Control:Max-Age=604800 to the response headers in the request.
I have added the following code my apps AppDelegate.m file:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
//set up the URL cache
NSURLCache *URLCache = [[NSURLCache alloc] initWithMemoryCapacity:4 * 1024 * 1024
diskCapacity:20 * 1024 * 1024
diskPath:nil];
[NSURLCache setSharedURLCache:URLCache];
}
And my request in the code looks like this:
NSString *myURLString = [NSString stringWithFormat:#"http://domain.com/api/?location=%#,%#&date=%#&method=%#", latitude, longitude, curDate, methodString];
NSLog(#"%#", myURLString);
NSURL *url = [NSURL URLWithString:myURLString];
NSData *jsonData = [NSData dataWithContentsOfURL:url];
I do not think this is working, because when running with instruments network profile I see a spike in network request each time the view is loaded and if I load the app then put the phone in plane mode no data loads (whereas I suspect it would use the cache).
Is this proof that no cache is being made/used? And, if so, does anyone have any ideas why not? And, if it's not proof, does anyone know how I can better test the caching?
Many thanks.
+[NSData dataWithContentsOfURL:] makes absolutely no guarantees about what caching model it will follow. In practice at present, it deliberately ignores any cache.
You should instead use NSURLConnection which exposes proper caching controls.