NSURLCache - disk caching for GET request with broken parameters

I am trying to cache some HTTP requests to disk using NSURLCache. After doing some tests with AFNetworking and not working, I created a simple example using NSURLRequest.

I initialize the cache on the AppDelegate as follows, setting the memory size to 0, forcing it to always access disk:

NSUInteger sz = 1024*1024*20;
NSURLCache *cache = [[NSURLCache alloc] initWithMemoryCapacity:0 diskCapacity:sz diskPath:nil];
[NSURLCache setSharedURLCache:cache];

      

I am using the following code to store the response:

NSURLCache * urlCache = [NSURLCache sharedURLCache];

NSString *urlString = @"http://localhost:8000/cities/api/cities/?lang=en";
NSHTTPURLResponse *response = nil;
NSError *error = nil;

NSURL *finalUrl = [NSURL URLWithString:urlString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:finalUrl];
request.cachePolicy = NSURLRequestReturnCacheDataElseLoad;

NSData *data = nil;

data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];

NSCachedURLResponse *cachedResponse = [[NSCachedURLResponse alloc] initWithResponse:response data:data userInfo:nil storagePolicy:NSURLCacheStorageAllowed];
[urlCache storeCachedResponse:cachedResponse forRequest:request];

      

My request has HTTP header cache control like:

response ['cache-control'] = 'max-age = 36000, public'

I can see that the response is cached in the Cache.db file.

And later, in the next performance or even the same, I use the following code to try and get the response from Cache:

NSCachedURLResponse *cachedResponse = [urlCache cachedResponseForRequest:request];
response = cachedResponse.response;
data = cachedResponse.data;

      

The problem is that cachedResponse is always null when the request has GET parameters on it . If the request is " http: // localhost: 8000 / cities / api / cities / , the result is saved and restored later. But when it has GET parameters, something is preventing the [NSURLCache cachedResponseForRequest: request] method from finding the request."

Providing this, I subclassed NSURLCache and implemented this method like this:

- (id)initWithMemoryCapacity:(NSUInteger)memoryCapacity diskCapacity:(NSUInteger)diskCapacity diskPath:(NSString *)path {
self = [super initWithMemoryCapacity:memoryCapacity diskCapacity:diskCapacity diskPath:path];
if (self) {
    NSArray *docPaths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
    NSString *dir = (NSString*)[docPaths objectAtIndex:0];
    dir = [dir stringByAppendingString:@"/uk.co.airsource.TestURLCache/nsurlcache"];
    NSString *path = [dir stringByAppendingFormat:@"/Cache.db"];
    self.db = [[FMDatabase alloc] initWithPath:path];
    [self.db open];
    int o = 4;
}
return self;

      

}

- (NSCachedURLResponse *) cachedResponseForRequest:(NSURLRequest *)request {
NSCachedURLResponse *cachedURLResponse = [super cachedResponseForRequest:request];
if (cachedURLResponse == nil && [request.HTTPMethod isEqualToString:@"GET"]) {
    //[db executeQuery:@"select * from test where a = ?", @"hi'",  nil];
    NSLog(@"%@", request.URL.absoluteString);
    FMResultSet *cfurl_cache_response = [self.db executeQuery:@"select * from cfurl_cache_response where request_key = ? limit 1", request.URL.absoluteString, nil];
    if ([cfurl_cache_response next]) {
        id entry_ID = [cfurl_cache_response objectForColumnName:@"entry_ID"];
        [cfurl_cache_response close];
        if (entry_ID != [NSNull null]) {
            FMResultSet *cfurl_cache_blob_data = [self.db executeQuery:@"select * from cfurl_cache_blob_data where entry_ID = ? limit 1", entry_ID, nil];
            if ([cfurl_cache_blob_data next]) {
                id response_object = [cfurl_cache_blob_data objectForColumnName:@"response_object"];
                [cfurl_cache_blob_data close];
                FMResultSet *cfurl_receiver_data = [self.db executeQuery:@"select * from cfurl_cache_receiver_data where entry_ID = ? limit 1", entry_ID, nil];
                if ([cfurl_receiver_data next]) {
                    id receiver_data = [cfurl_receiver_data objectForColumnName:@"receiver_data"];
                    [cfurl_receiver_data close];
                    if (response_object != [NSNull null] && receiver_data != [NSNull null] && response_object && receiver_data) {
                        NSURLResponse *urlResponse = [[NSURLResponse alloc] initWithURL:request.URL MIMEType:[[request allHTTPHeaderFields] objectForKey:@"Accept"] expectedContentLength:[(NSData *)response_object length] textEncodingName:nil];
                        cachedURLResponse = [[NSCachedURLResponse alloc] initWithResponse:urlResponse data:receiver_data userInfo:nil storagePolicy:NSURLCacheStorageAllowed];
                    }
                }
            }
        }
    }
}
return cachedURLResponse;

      

}

In this case, according to the GET request with parameters, it executes each individual line until it receives the previously saved NSURLResponse.

Any ideas as to why it doesn't work fine when the request has GET parameters?

DB with the 2 requests stored

+3


source to share


2 answers


Finally, I overridden NSURLCache to achieve what I was looking for:

  • GET requests (with parameters) are cached to disk
  • Requests being sent to the cache while the Max Cache Increase value indicates that it has not expired and after expiration it is returned to the server saving a new response and starting to expire
  • Offline always return the response (if it exists) from the cache


NTURLCache - overrides NSURLCache

I seriously think this is a problem that does not work as expected in iOS 8.1

0


source


The problem was not to specify the amount of memory if you specify the amount of memory like this:

Here I point out that the memory is 1MB in size

[[NSURLCache alloc] initWithMemoryCapacity:1*1024*1024 diskCapacity:sz diskPath:nil];

      



it will work, it seems to me that the amount of memory is needed no matter how small the capacity is, but cannot be empty. Then you should be able to extract the saved cached file like this:

NSCachedURLResponse *cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:request];
response = cachedResponse.response;
data = cachedResponse.data;

      

+1


source







All Articles