iOS7 brings NSURLSession
, with the help of NSURLSessionConfigure
, we can customize URLCache, so i tried it, but with no luck, it seems my URLCache is not used at all.
- (void)testURLCache
{
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
config.requestCachePolicy = NSURLRequestUseProtocolCachePolicy;
NSURLCache *cache = [[NSURLCache alloc] initWithMemoryCapacity:1024 * 100 diskCapacity:1024 * 100 diskPath:@"test.urlcache"];
NSLog(@"usage:%lu", (unsigned long)[cache currentDiskUsage]);
config.URLCache = cache;
NSURLSession *session = [NSURLSession sessionWithConfiguration:config];
for (int i = 0; i < 40; i++) {
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://ajax.googleapis.com/ajax/libs/angularjs/1.2.6/angular.min.js?%d", i]]];
NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) {
NSLog(@"error:%@", error);
} else {
NSLog(@"done:%d", i);
}
}];
[task resume];
[NSThread sleepForTimeInterval:0.5];
}
NSLog(@"usage:%lu", (unsigned long)[cache currentDiskUsage]);
}
something i observed:
1) a test.urlcache
folder is created under Caches
folder, and with 3 files Cache.db
, Cache.db-shm
, Cache.db-wal
, the size of Cache.db
is 4KB, no records in it.
2) every time run the code, the first output of usage is always 0, after for loop ended, usage becomes 4096, the next time usage becomes 0 again.
This is iOS7 issue. With iOS8.1 it works correctly, I'm not sure about iOS8. Please notice also you can still use iOS7 SDK to compile your app, and it'll work correctly on iOS8.1 devices.
However you may still use global cache, instead of the one assigned to
NSURLSessionConfiguration
:BTW, in iOS8 there are 3 not yet documented methods in
NSURLCache
class (actually it is aNSURLSessionTaskAdditions
category ofNSURLCache
, check NSURLCache.h file):...however it's not neccessary to touch them is you want to change caching mechanics ;)
Seems like there are two potential issues:
Your cache is too small. Historically, it wouldn't cache if the item being cached exceeded 10% of the total cache size.
You're checking the disk usage 0.5 seconds after the last request. That might be too soon for the cache to be written to persistent storage.
Below I use a bigger cache and wait 10 seconds before final check of disk usage, and the cache works fine. I also use GCD to queue the serial tasks to eliminate the arbitrary 0.5 second delay, which is both safer, and makes it more obvious when it's retrieving data over network and when it's using the cache.
As an aside, for network tasks like this, I'd generally use operation queue rather than dispatch queue and then wrap my data tasks in concurrent
NSOperation
subclass. Then I can use dependencies to dictate the final completion operation, but at the same time both permit concurrency but also dictate the degree of concurrency, but this seemed outside the scope of the original question and I wanted to keep this as simple as possible.