Lê Khánh Vinh Lê Khánh Vinh - 3 months ago 56
iOS Question

Implement custom cache for AFNetworking 3.x

Hi I'm writing a IOS api to fetch data from server using AFNetworking 3.x My Server does not support caching. This this server header

Connection →Keep-Alive
Content-Length →4603
Content-Type →text/html; charset=UTF-8
Date →Wed, 10 Aug 2016 04:03:56 GMT
Keep-Alive →timeout=5, max=100
Server →Apache/2.4.18 (Unix) OpenSSL/1.0.1e-fips PHP/5.4.45
X-Powered-By →PHP/5.4.45


I want to build custom API to enable cache (for example request and response should be cache for 10 second so that if user make same request, cache data is used. If cache expired app will then re download again)

My
AFNetworking
Singleton

#pragma mark - Shared singleton instance

+ (ApiClient *)sharedInstance {
static ApiClient *sharedInstance = nil;
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
sharedInstance = [[self alloc] initWithBaseURL:[NSURL URLWithString:SINGPOST_BASE_URL] sessionConfiguration:sessionConfiguration];

return sharedInstance;
}

- (id)initWithBaseURL:(NSURL *)url
{
if ((self = [super initWithBaseURL:url])) {
self.requestSerializer = [AFHTTPRequestSerializer serializer];
}
return self;
}


My JSON request

- (void)sendJSONRequest:(NSMutableURLRequest *)request
success:(void (^)(NSURLResponse *response, id responseObject))success
failure:(void (^)(NSError *error))failure {

self.responseSerializer.acceptableContentTypes = [AFHTTPResponseSerializer serializer].acceptableContentTypes;
self.requestSerializer.timeoutInterval = 5;
self.requestSerializer.cachePolicy = NSURLRequestReturnCacheDataElseLoad;

[self setDataTaskWillCacheResponseBlock:^NSCachedURLResponse * _Nonnull(NSURLSession * _Nonnull session, NSURLSessionDataTask * _Nonnull dataTask, NSCachedURLResponse * _Nonnull proposedResponse) {
return [[NSCachedURLResponse alloc] initWithResponse:proposedResponse.response
data:proposedResponse.data
userInfo:proposedResponse.userInfo
storagePolicy:NSURLCacheStorageAllowed];
}];

NSURLSessionDataTask *dataTask = [ApiClient.sharedInstance dataTaskWithRequest:request completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {
if (error) {
NSLog(@"Error URL: %@",request.URL.absoluteString);
NSLog(@"Error: %@", error);
failure(error);
} else {
NSDictionary *jsonDict = (NSDictionary *) responseObject;
success(response,jsonDict);
NSLog(@"Success URL: %@",request.URL.absoluteString);
NSLog(@"Success %@",jsonDict);
}
}];
[dataTask resume];

}


How to modify the bellow code to enable caching request and response (I want response to be keep like 10 sec) (Or 1 day if no internet connection) Any help is much appreciate. Thanks!

[self setDataTaskWillCacheResponseBlock:^NSCachedURLResponse * _Nonnull(NSURLSession * _Nonnull session, NSURLSessionDataTask * _Nonnull dataTask, NSCachedURLResponse * _Nonnull proposedResponse) {
return [[NSCachedURLResponse alloc] initWithResponse:proposedResponse.response
data:proposedResponse.data
userInfo:proposedResponse.userInfo
storagePolicy:NSURLCacheStorageAllowed];
}];

Answer

Instead of

            return [[NSCachedURLResponse alloc] initWithResponse:proposedResponse.response

do

            NSMutableDictionary *dictionary = [proposedResponse.response.allHeaderFields mutableCopy];
            dictionary[@"Cache-Control" = ...
            NSHTTPURLResponse *modifiedResponse =
              [[NSHTTPURLResponse alloc initWithURL:proposedResponse.response.URL
                                         statusCode:proposedResponse.response.statusCode
                                        HTTPVersion:@"HTTP/1.1"
                                       headerFields:modifiedHeaders];

            [modifiedResponse 
            return [[NSCachedURLResponse alloc] initWithResponse:modifiedResponse

Note that it is not possible to retrieve the HTTP version from the original request. I'm pretty sure I filed a bug about that. I'm also pretty sure that it doesn't have any effect on anything, and I don't think it even gets stored in the underlying object, so it probably doesn't matter.

Comments