Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AFNetworking 2.0 - Forced caching

Is it possible to force response caching if it contains neither Expires or Cache-Control: max-age?

I've came across this article, but unfortunately URLSession:dataTask:willCacheResponse:completionHandler: never gets called in my AFHTTPSessionManager subclass.

Any help appreciated.

like image 211
Attila H Avatar asked Aug 30 '14 19:08

Attila H


1 Answers

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.
like image 101
Aaron Brager Avatar answered Oct 04 '22 20:10

Aaron Brager