我可以在iOS上使用NSURLSessionDownloadTask进行HTTP缓存吗?

Nic*_*eet 9 ios

我正在尝试使用NSURLSessionDownloadTask,并利用Apple的内置URL缓存功能.NSURLSessionDataTask使用下面的代码时,我已经成功地使缓存工作:

- (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"]];
}
Run Code Online (Sandbox Code Playgroud)

但是,我需要执行后台下载,我必须使用NSURLDownloadTask.切换到此时,不会发生缓存行为.

- (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"]];
}
Run Code Online (Sandbox Code Playgroud)

Apple的此文档表明NSURLDownloadTasks不调用URLSession:dataTask:willCacheResponse:completionHandler:委托方法,因此您的应用程序无法挂钩缓存生命周期.我的猜测是,这意味着缓存根本不适用于这些任务,但对此并不明确.

  1. 对于数据任务,该NSURLSession对象调用委托的URLSession:dataTask:willCacheResponse:completionHandler:方法.然后,您的应用应决定是否允许缓存.如果未实现此方法,则默认行为是使用会话配置对象中指定的缓存策略.

任何人都可以确认这一预感NSURLSessionDownloadTasks根本不支持缓存吗?是否有可能在后台任务中利用Apple的HTTP缓存行为?

que*_*ish 10

NSURLSessionDownloadTask使用在应用程序进程外执行下载的系统服务(守护程序)执行工作.因此,实际上为下载任务调用的委托回调比那些更有限NSURLSessionDataTask.如URL会话的生命周期中所述,数据任务委托将接收回调以自定义缓存行为,而下载任务委托则不会.

下载任务应该使用由其指定的缓存策略NSURLRequest,并且应该使用指定的缓存存储NSURLSessionConfiguration(如果没有,则提交bug).默认缓存策略是NSURLRequestUseProtocolCachePolicy,默认URL缓存存储是非后台和非短暂配置的共享URL缓存.委托回调URLSession:dataTask:willCacheResponse:completionHandler:并不是实际发生的缓存的良好指标.

如果NSURLSessionDownloadTask使用默认会话配置创建并且不自定义NSURLRequests 的缓存策略,则缓存已经发生.

  • 我已经构建了一个框架测试项目,允许您触发下载和数据任务,同时通过 Charles 检查 HTTP 流量。所有初始的 `NSURLSessionDownloadTask` 请求都会发出 HTTP 请求,因此不会发生缓存。第一个 `NSSessionDataTask` 调用一个请求,但任何类型的所有后续请求都不会调用 HTTP 请求,因为 iOS 正在使用缓存副本。本质上,“NSURLSessionDownloadTask”将使用现有缓存,但不会添加到其中。查看项目来演示这个:https://github.com/nickstreet/CacheTest (2认同)

Gle*_*Low 9

看起来好像NSURLSessionDownloadTask没有缓存,按设计.

NSURLSessionConfiguration文档

defaultSessionConfiguration方法记录在案:

默认会话配置使用基于磁盘的持久缓存(除非将结果下载到文件中),并将凭据存储在用户的密钥链中.

但是,没有其他构造函数被记录为排除上述斜体异常.我也测试了backgroundSessionConfigurationWithIdentifier它似乎也没有做到这一点.

此外,requestCachePolicy也没有提供任何出于例外的方法.

NSURLSessionDownloadTask运行时效率

NSURLSessionDownloadTask将传入数据写入临时文件.完成文件后,它会通知委托或完成处理程序.最后它删除文件.

虽然它可以简单地将文件移动到缓存中,但它必须处理委托或完成处理程序实际修改文件,从而更改其缓存的表示,甚至将文件移动到永久位置,它无法跟踪.

它可以通知委托或完成处理程序之前复制文件,但这对于大文件来说效率低下.

它可以将文件保持为只读,但在iOS 8.0上似乎不会这样做.

因此,系统不太可能对下载任务进行任何缓存.

解决方法

您最好的选择是使用NSURLSessionDataTask,然后在URLSession:dataTask:didReceiveData:调用您的委托方法时,将传入的数据附加到您自己的文件中.下次使用时,NSURLSessionDataTask您可以在一次调用中获取缓存数据URLSession:dataTask:didReceiveData:.