24

AFNetworking HTTP Cache

When developing iOS application that requires network communication, I frequently use AFNetworking library. It’s good to know that iOS along with AFNetworking supports HTTP Cache out of the box.

Unfortunately, when server returns code 304 “Not Modified”, iOS loads cached response in background and returns it to the user, as it would be returned from server. Because of that, you can’t implement different logic depending on data modification state. Investigating how AFNetworking works, gets me nice solution to that issue.

I found a way to determine if response was returned from cache or not, using AFNetworking 2.0. 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 object 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;
    }];

Perhaps your app is doing some heavy processing of returned data, for example parsing JSON and updating CoreData content. You can assume that if response is returned from cache the whole processing can be skipped, saving user’s time. That way you will take full advantage of HTTP Cache implementation on the client side.

  1. Shwetabh says:

    Even with status code 304, success does not run. it always enters the failure block. why is this??

    • Darrarski says:

      What kind of error your are receiving? Check error’s domain and code, log out NSError description or localizedDescription. It will help you finding the reason.

      • Shwetabh says:

        Actually, I am getting RESPONSE FROM CACHE: , that is nil when the response from server is 304. My cachedResponse is not getting cached.
        It works fine for server response 200.

        • Darrarski says:

          Check if the block you set using setCacheResponseBlock is called when server returns status code 200. It could be that your server HTTP Cache configuration is not working properly. Unfortunately in that case, my solution is not working like expected. It’s also possible that something changed in AFNetworking recently, I am not able to verify if my solution is still valid at the moment.

  2. pratusha says:

    can u tell me how we can cache server response if we i am using afnetworking

  3. Ganesh says:

    I use following block of code for POST request.

    [manager POST:urlString
    parameters:parameters
    success:^(AFHTTPRequestOperation *operation, id responseObject)
    {

    NSLog(@”JSON: %@”,responseObject);
    NSLog(@”response statuscode : %ld”,(long)operation.response.statusCode); //This prints 200

    }
    failure:^(AFHTTPRequestOperation *operation, NSError *error)
    {

    NSLog(@”Error: %@”,[error localizedDescription]);

    }];

    I don’t want to load the cached response. My application need to update from web service whenever I call request manually. But all the time I get cached response only. The response is not getting updated.

Comments are closed.