Is it possible to prevent an NSURLRequest from caching data or remove cached data following a request?
Asked Answered
L

6

90

On iPhone, I perform a HTTP request using NSURLRequest for a chunk of data. Object allocation spikes and I assign the data accordingly. When I finish with the data, I free it up accordingly - however instruments doesn't show any data to have been freed!

My theory is that by default HTTP requests are cached, however - I don't want my iPhone app to cache this data.

Is there a way to clear this cache after a request or prevent any data from being cached in the first place?

I've tried using all the cache policies documented a little like below:

NSMutableURLRequest *theRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]];
theRequest.cachePolicy = NSURLRequestReloadIgnoringLocalCacheData;

but nothing seems to free up the memory!

Lolalolande answered 1/1, 2009 at 16:58 Comment(2)
Would it be possible it's not cache related? Have you tried inspecting the data to see if data that should have been reloaded is in fact the old one? Maybe your leek is coming from elsewhere. How do you initialize and free the NSURLRequests? That might be of help to diagnose the problem.Liking
FYI – If you want to remove the files by brute force, there is example code to do that here: salesforce.stackexchange.com/a/69736Accumbent
R
159

Usually it's easier to create the request like this

NSURLRequest *request = [NSURLRequest requestWithURL:url
      cachePolicy:NSURLRequestReloadIgnoringCacheData
      timeoutInterval:60.0];

Then create the connection

NSURLConnection *conn = [NSURLConnection connectionWithRequest:request
       delegate:self];

and implement the connection:willCacheResponse: method on the delegate. Just returning nil should do it.

- (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse {
  return nil;
}
Reube answered 2/1, 2009 at 2:30 Comment(12)
Thanks for that idea - I was calling a SOAP web service like this repeatedly and it was growing the heap uncontrollably even though leaks didn't show anything was wrong. I optimized for days and finally tried to prevent caching since a lot of CFURL* objects from the internal framework were hanging around. Returning nil from willCacheResponse was the only thing that worked!Gyp
this is really helpful in case of background apps when they are trying to acces same url :) thax!Ruffled
Why is it necessary to do both NSURLRequestReloadIgnoringCacheData and implement connection:willCacheResponse:?Nembutal
Hi, is it possible that I can use this for loading local content? The above is for NSUrlConnection but i'm loading local HTML data into UIWebView using NSUrlRequest. I need to reject any caching as there are images going into the webview from SQLite and memory is increasing with every page load. Thanks.Cooperstein
@fabb, overriding connection:willCacheResponse: allows you to not store the response in the cache. NSURLRequestReloadIgnoringCacheData specifies that the connection should load the request without checking the cache. The former is presumably what helps manage memory allocation.Windsor
Curiously, connection:willCacheResponse: is not documented as a method of NSURLConnectionDelegate on the Apple website.Blynn
@HotLicks It is, indeed a required method Return Value The actual cached response to store in the cache. The delegate may return cachedResponse unmodified, return a modified cached response, or return nil if no cached response should be stored for the connection.Coussoule
@Coussoule -- Ah, it's long deprecated in iOS. Didn't look at OSx.Blynn
@HotLicks -- It's availiable in iOS 5.0 and later as part of the NSURLConnectionDataDelegate. developer.apple.com/library/ios/documentation/Foundation/…Paget
Pardon a n00b, but how exactly does one read the response data from the web page with this approach? When using the sendSynchronousRequest method you get NSData back, but with the approach here you get a connection object back. How do you get the response HTML/JSON/data from the connection object?Kelcy
@Lev that's not the right place for questions like that - but read up on delegates.Reube
@Reube I was aware of the delegate already, just not which methods or approach to use. ;P In any event, I stumbled upon a tutorial yesterday which helped me figure it out.Kelcy
P
12

I have the same problem in my app when I requested info from twitter. In my case I didn't need to preserve those credentials, so I simple erase them using the next code:

- (void) eraseCredentials{
NSURLCredentialStorage *credentialsStorage = [NSURLCredentialStorage sharedCredentialStorage];
NSDictionary *allCredentials = [credentialsStorage allCredentials];

//iterate through all credentials to find the twitter host
for (NSURLProtectionSpace *protectionSpace in allCredentials)
    if ([[protectionSpace host] isEqualToString:@"twitter.com"]){
        //to get the twitter's credentials
        NSDictionary *credentials = [credentialsStorage credentialsForProtectionSpace:protectionSpace];
        //iterate through twitter's credentials, and erase them all
        for (NSString *credentialKey in credentials)
            [credentialsStorage removeCredential:[credentials objectForKey:credentialKey] forProtectionSpace:protectionSpace];
    }
}

I hope it works for somebody :)

Puerile answered 8/10, 2009 at 8:30 Comment(2)
this was a perfect solution for my problem, i had relogin problem, since the credentials were stored and were automatically being submitted by the NSURLConnection, thanks a lot this helped me big time :)Anti
Thanks it's work for me, i am really appreciate your suggestion. Actually My problem is that NSURLRequest storing username and password. So this help to remove User credential from cache...Odessaodetta
P
10

If you use NSURLConnection take a look at the delegate:

- (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse

Return Value

The actual cached response to store in the cache. The delegate may return cachedResponse unmodified, return a modified cached response, or return nil if no cached response should be stored for the connection.

Packer answered 1/1, 2009 at 23:55 Comment(1)
Thanks so much here. The memory footprint of my app has suddenly halved! Nick.Lolalolande
C
10

If you're using NSURLSession, another solution to prevent request and parameters being written to the Cache.db iOS creates within the app's Caches directory, is to set the NSURLCache for the session's configuration to a 0 size memory and 0 size disk cache e.g.

let configuration = URLSessionConfiguration.default    
configuration.urlCache = URLCache(memoryCapacity: 0, diskCapacity: 0, diskPath: nil)
let session = URLSession(configuration: configuration)

or as mentioned above set at a global cache level

URLCache.shared = URLCache(memoryCapacity: 0, diskCapacity: 0, diskPath: nil)

Presumably it's the 0 for disk size that stops iOS writing to disk but if you have a policy to reloadIgnoringLocalCacheData then you probably aren't interested in memory caching either.

Note This will prevent any Caches/Cache.db (requests & responses) or Caches/fsCachedData/ folder (response data) being created at all. We've decided to take this approach in an app for security purposes as we don't want our requests to be stored on disk cache ever.

If anyone knows is there's a way to stop only request caching but keep response data caching from the iOS URL Loading mechanism, I'd be interested to know. (there's no API or official documentation about this from what I can tell)

Cowitch answered 9/10, 2016 at 11:17 Comment(1)
Did you ever found an answer for this question?Square
A
7

If not specific to a single request(U want disable cache for whole app) below one is the best option.Add this code in app delegate or based on ur need any where

        int cacheSizeMemory = 0; // 0MB
        int cacheSizeDisk = 0; // 0MB
        NSURLCache *sharedCache = [[NSURLCache alloc] initWithMemoryCapacity:cacheSizeMemory diskCapacity:cacheSizeDisk diskPath:@"nsurlcache"];
        [NSURLCache setSharedURLCache:sharedCache];
Antipasto answered 30/6, 2014 at 13:43 Comment(1)
Works great for me, but you can just use 0 rather than doing the multiplication that just ends up at 0 anyways.Contrapuntist
C
3
NSMutableURLRequest* request = [[NSMutableURLRequest alloc] url];
[request setValue:@"no-store" forHTTPHeaderField:@"Cache-Control"];
[request setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData];

Assuming the server is correctly implemented, putting the Cache-Control:no-store header in the request will generate a server response with the same header, thus causing NSURLCache to not store the response data on disk.

Therefore, no need for the shotgun approach of disabling NSURLCache disk caching.

PS: Adding the header should work for all HTTP frameworks, like AFNetworking

Cherlycherlyn answered 14/8, 2017 at 21:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.