Afnetworking - Do Not Cache Response

AFNetworking - do not cache response

Make long story short, just define your AFNetworking manager:

AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager.requestSerializer setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData];

Enjoy!

How To Disable AFNetworking Cache

Cacheing is handled application-wide by NSURLCache. If you don't set a shared cache, requests are not cached. Even with a shared NSURLCache, the default implementation on iOS does not support disk cacheing anyway.

That said, unless you have a very particular reason to write your own cacheing system, I would strongly recommend against it. NSURLCache is good enough for 99.9% of applications: it handles cache directives from incoming responses and uses them appropriately with new requests, and does so automatically in a way that is unlikely to be a performance bottleneck in your application. As someone who has wasted untold hours making one myself (and later throwing it away since it was completely unnecessary), I'd say that there are much better places to focus your development attention.

AFNetworking disable caching

Cache behavior can be set on NSMutableURLRequest objects, with setCachePolicy:. Otherwise, the built-in shared NSURLCache will respect the caching behavior defined by the server (which I would recommend tuning and taking advantage of, rather than outright disregarding).

AFNetworking : How to know if response is using cache or not ? 304 or 200

I think I found a solution to determine if response was returned from cache or not using AFNetworking 2.0. I found out that each time a new response is returned from the server (status 200, not 304) the cacheResponseBlock which is a property of AFHTTPRequestOperation is called. The block should return NSCachedURLResponse if response should be cached or nil if it shouldn't. That's way you can filter responses and cache only some of them. In this case, I am caching all responses that comes from the server. The trick is, that when server sends 304 and response is loaded from cache, this block won't be called. So, this is the code I am using:

AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];

BOOL __block responseFromCache = YES; // yes by default

void (^requestSuccessBlock)(AFHTTPRequestOperation *operation, id responseObject) = ^(AFHTTPRequestOperation *operation, id responseObject) {
if (responseFromCache) {
// response was returned from cache
NSLog(@"RESPONSE FROM CACHE: %@", responseObject);
}
else {
// response was returned from the server, not from cache
NSLog(@"RESPONSE: %@", responseObject);
}
};

void (^requestFailureBlock)(AFHTTPRequestOperation *operation, NSError *error) = ^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"ERROR: %@", error);
};

AFHTTPRequestOperation *operation = [manager GET:@"http://example.com/"
parameters:nil
success:requestSuccessBlock
failure:requestFailureBlock];

[operation setCacheResponseBlock:^NSCachedURLResponse *(NSURLConnection *connection, NSCachedURLResponse *cachedResponse) {
// this will be called whenever server returns status code 200, not 304
responseFromCache = NO;
return cachedResponse;
}];

This solution works for me and I haven't found any issues so far. But, if you have a better idea or some objections against my solution, feel free to comment!

AFNetworking 2.0 - Forced caching

You can force the caching by implementing your own NSURLProtocol that does not follow the standard HTTP caching rules. A complete tutorial is here, which persists the data using Core Data, but the basic steps are:

  • Subclass NSURLProtocol
  • Register your subclass with +registerClass:
  • Return YES in your +canInitWithRequest: method if this is the first time you've seen request, or NO if it isn't

You now have two choices:

  1. Implement your own cache storage (in which case, follow the tutorial linked above)
  2. Inject the cache control headers that you wish the URL loading system to follow

Assuming you want #2, override connection:didReceiveResponse: in your protocol subclass to create a response that has the cache control headers you want to emulate:

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSHTTPURLResponse *)response {
// Create a dictionary with the headers you want
NSMutableDictionary *newHeaders = [response.allHeaderFields mutableCopy];
newHeaders[@"Cache-Control"] = @"no-transform,public,max-age=300,s-maxage=900";

// Create a new response
NSHTTPURLResponse *newResponse = [[NSHTTPURLResponse alloc] initWithURL:response.URL
statusCode:response.statusCode
HTTPVersion:@"HTTP/1.1"
headerFields:newHeaders];

[self.client URLProtocol:self
didReceiveResponse:newResponse
cacheStoragePolicy:NSURLCacheStorageAllowed];
}

This will cause the response to be cached as if the server had provided these headers.


For URL sessions only, you need to set the session configuration's protocolClasses. Since you're using AFNetworking, that looks like:

[AFHTTPSessionManager sharedManager].session.configuration.protocolClasses = @[[MyURLProtocol class]]

There are some caveats, so make sure you read the protocolClasses documentation.


A few notes:

  • If there's any way to fix this by having your server send the appropriate headers, please, please do that instead.
  • For the sake of brevity I hardcoded "HTTP/1.1", but technically you should pull this out of the response.
  • AFNetworking uses the standard URL Loading System, and is mostly unrelated to this issue.


Related Topics



Leave a reply



Submit