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

时间:2014-10-03 07:45:29

标签: ios

我正在尝试使用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委托方法,因此您的应用无法挂钩缓存生命周期。我的猜测是,这意味着缓存根本无法用于这些任务,但对此并不明确。

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

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

3 个答案:

答案 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()
}