我正在尝试使用NSURLSessionDownloadTask
,并利用Apple内置的URL缓存功能。使用下面的代码{@ 1}}时,我已经成功地使缓存工作了:
NSURLSessionDataTask
但是,我需要执行后台下载,我必须使用NSURLDownloadTask。切换到此时,不会发生缓存行为。
- (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"]];
}
来自Apple的 This documentation表示- (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"]];
}
没有调用NSURLDownloadTasks
委托方法,因此您的应用无法挂钩缓存生命周期。我的猜测是,这意味着缓存根本无法用于这些任务,但对此并不明确。
- 对于数据任务,
醇>URLSession:dataTask:willCacheResponse:completionHandler:
对象会调用委托的NSURLSession
方法。您的 应该应用程序应该决定是否允许缓存。如果你不 实现此方法,默认行为是使用缓存 会话的配置对象中指定的策略。
任何人都可以确认这一预感NSURLSessionDownloadTasks根本不支持缓存吗?是否可以在后台任务中利用Apple的HTTP缓存行为?
答案 0 :(得分:9)
NSURLSessionDownloadTask
使用在应用程序进程外执行下载的系统服务(守护程序)执行工作。因此,实际为下载任务调用的委托回调比NSURLSessionDataTask
的回调更受限制。如Life Cycle of a URL Session中所述,数据任务委托将接收回调以自定义缓存行为,而下载任务委托则不会。
下载任务应该使用NSURLRequest
指定的缓存策略,并且应该使用NSURLSessionConfiguration
指定的缓存存储(如果没有,则提交错误)。默认缓存策略为NSURLRequestUseProtocolCachePolicy
,默认URL缓存存储是非后台和非短暂配置的共享URL缓存。 URLSession:dataTask:willCacheResponse:completionHandler:
的委托回调并不是实际发生缓存的良好指标。
如果使用默认会话配置创建NSURLSessionDownloadTask
并且不自定义NSURLRequest
的缓存策略,则缓存已经发生。
答案 1 :(得分:8)
看起来NSURLSessionDownloadTask
没有按设计缓存。
NSURLSessionConfiguration文档
记录了defaultSessionConfiguration
方法:
默认会话配置使用基于磁盘的持久缓存(结果下载到文件除外)并将凭据存储在用户的密钥链中。
但是,没有其他构造函数被记录为排除上述斜体异常。我也测试了backgroundSessionConfigurationWithIdentifier
,它似乎也没有完成这项工作。
此外,requestCachePolicy
也没有提供任何超出异常的方法。
NSURLSessionDownloadTask运行时效率
NSURLSessionDownloadTask
将传入的数据写入临时文件。完成文件后,它会通知委托或完成处理程序。最后删除文件。
虽然它可以简单地将文件移动到缓存中,但它必须处理委托或完成处理程序实际修改文件,从而更改其缓存的表示,甚至将文件移动到永久位置,它可以跟踪。
它可以在通知委托或完成处理程序之前复制文件,但这对于大文件来说效率很低。
它可以将文件保持为只读,但在iOS 8.0上似乎不会这样做。
因此,系统不太可能对下载任务进行任何缓存。
解决方法强>
您最好的选择是使用NSURLSessionDataTask
,然后在调用委托的URLSession:dataTask:didReceiveData:
方法时,将传入的数据附加到您自己的文件中。下次使用NSURLSessionDataTask
时,您只需一次调用URLSession:dataTask:didReceiveData:
即可获得缓存数据。
答案 2 :(得分:0)
只有强行存储响应才能使它起作用
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
let uRLCache = URLCache(memoryCapacity: 500 * 1024 * 1024, diskCapacity: 500 * 1024 * 1024, diskPath: nil)
URLCache.shared = uRLCache
}
func download() {
let req = URLRequest(url: remoteurl, cachePolicy: URLRequest.CachePolicy.returnCacheDataElseLoad, timeoutInterval: 30)
if let cachedResponse = URLCache.shared.cachedResponse(for: req) {
print("found")
}
let downloadTask = URLSession.shared.downloadTask(with: req, completionHandler: { [weak self] (url, res, error) -> Void in
guard let `self` = self else { return }
if let data = try? Data(contentsOf: url), res != nil && URLCache.shared.cachedResponse(for: req) == nil {
// store the response
URLCache.shared.storeCachedResponse(CachedURLResponse(response: res!, data: data), for: req)
}
})
downloadTask?.resume()
}