I'm trying to use NSURLSessionDownloadTask
, and take advantage of Apple's in-built URL caching functionality. I have succeeded in getting the caching to work when using an NSURLSessionDataTask
using the code below:
- (void)downloadUsingNSURLSessionDataTask:(NSURL *)url {
NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfig delegate:self delegateQueue:nil];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request];
[dataTask resume];
}
- (void)cachedDataTaskTest {
// This call performs an HTTP request
[self downloadUsingNSURLSessionDataTask:[NSURL URLWithString:@"http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"]];
[NSThread sleepForTimeInterval:1];
// This call returns the locally cached copy, and no HTTP request occurs
[self downloadUsingNSURLSessionDataTask:[NSURL URLWithString:@"http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"]];
}
However, I need to perform a background download for which I have to use an NSURLDownloadTask. When I switch to this the caching behaviour does not occur.
- (void)downloadUsingNSURLSessionDownloadTask:(NSURL *)url {
NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfig delegate:self delegateQueue:nil];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithRequest:request];
[downloadTask resume];
}
- (void)cachedDownloadTaskTest {
// This call performs an HTTP request
[self downloadUsingNSURLSessionDownloadTask:[NSURL URLWithString:@"http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"]];
[NSThread sleepForTimeInterval:1];
// This call also performs an HTTP request
[self downloadUsingNSURLSessionDownloadTask:[NSURL URLWithString:@"http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"]];
}
This documentation from Apple indicates that NSURLDownloadTasks
don't call the URLSession:dataTask:willCacheResponse:completionHandler:
delegate method, so it is not possible for your app to hook into the caching life cycle. My guess is that this implies that caching is simply not available for these tasks, but it is not explicit about this.
- For a data task, the
NSURLSession
object calls the delegate’sURLSession:dataTask:willCacheResponse:completionHandler:
method. Your app should then decide whether to allow caching. If you do not implement this method, the default behavior is to use the caching policy specified in the session’s configuration object.
Can anyone confirm this hunch that NSURLSessionDownloadTasks simply don't support caching? Is it possible to take advantage of Apple's HTTP caching behaviour in a background task?
A mutable collection you use to temporarily store transient key-value pairs that are subject to eviction when resources are low.
The NSURLSession class and related classes provide an API for downloading data from and uploading data to endpoints indicated by URLs. Your app can also use this API to perform background downloads when your app isn't running or, in iOS, while your app is suspended.
NSURLSessionDownloadTask
performs work using a system service (daemon) that performs the download outside your application process. Because of this, the delegate callbacks that actually get invoked for a download task are more limited than those for NSURLSessionDataTask
. As documented in Life Cycle of a URL Session, a data task delegate will receive callbacks to customize caching behavior, while a download task delegate will not.
A download task should use the caching policy specified by the NSURLRequest
, and should use the cache storage specified by the NSURLSessionConfiguration
(if it does not, file a bug). The default cache policy is NSURLRequestUseProtocolCachePolicy
, and the default URL cache storage is the shared URL cache for non-background and non-ephemeral configurations. The delegate callbacks for URLSession:dataTask:willCacheResponse:completionHandler:
are not a good indicator of wether caching is actually occurring.
If you create an NSURLSessionDownloadTask
using the default session configuration and do not customize the cache policy of NSURLRequest
s, caching is already happening.
It looks like NSURLSessionDownloadTask
does not cache, by design.
NSURLSessionConfiguration documentation
The defaultSessionConfiguration
method is documented:
The default session configuration uses a persistent disk-based cache (except when the result is downloaded to a file) and stores credentials in the user’s keychain.
However, none of the other constructors are documented to exclude the above italicized exception. I also tested backgroundSessionConfigurationWithIdentifier
and it doesn't appear to do the job either.
Also, requestCachePolicy
doesn't offer any way out of the exception either.
NSURLSessionDownloadTask runtime efficiency
NSURLSessionDownloadTask
writes incoming data to a temporary file. When it completes the file, it notifies the delegate or completion handler. Finally it deletes the file.
While it could simply move the file into cache at the end, it would have to deal with either the delegate or completion handler actually modifying the file and thus changing its cached representation, or even moving the file to a permanent location it can't track.
It could copy the file before notifying the delegate or completion handler, but this would be inefficient for large files.
It could keep the file read-only, but doesn't appear to do so on iOS 8.0.
Therefore, it's unlikely that the system would do any caching of download tasks.
Workaround
Your best bet is use NSURLSessionDataTask
, then when your delegate's URLSession:dataTask:didReceiveData:
method is called, append the incoming data to your own file. The next time you use NSURLSessionDataTask
you get the cached data all in one call of URLSession:dataTask:didReceiveData:
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With