将 NSURLSessionDataTask 转换为具有后台支持的下载任务
Posted
技术标签:
【中文标题】将 NSURLSessionDataTask 转换为具有后台支持的下载任务【英文标题】:Converting NSURLSessionDataTask into a Download task with Background support 【发布时间】:2014-04-25 12:26:24 【问题描述】:在检查标题(长度和类型)之后,我需要使用后台功能下载某些文件(不是全部),但它必须在同一操作中,而不是创建新任务/请求(因为有时由于短时间内有很多连接,我从服务器收到错误)。 所以我开始任务:
NSURLSessionConfiguration *configuratione = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *sessione = [NSURLSession sessionWithConfiguration:configuratione delegate:self delegateQueue:nil];
NSURLSessionDataTask *datatask = [sessione dataTaskWithRequest:request];
[datatask resume];
然后,我知道当接收到第一个响应时,可以使用此委托将数据任务转换为下载任务:
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
didReceiveResponse:(NSURLResponse *)response
completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler
if(XXXXXXXXXX)
NSLog(@"transform into a download");
completionHandler(NSURLSessionResponseBecomeDownload);
else
NSLog(@"Keep loading normally");
completionHandler(NSURLSessionResponseAllow);
但是,由于数据任务不能使用 BackgroundSessionConfiguration,我想新创建的下载将使用相同的默认会话配置。 如何保持该下载在后台运行?有没有办法将它的会话更改为后台会话?或者是哪种方法?
【问题讨论】:
【参考方案1】:这个问题很难给出明确的答案,对我来说,所有 3 个主要的 URLLoading 因素(sessionType、taskType、FG/BG 创建)都受到您的设计的限制。 p>
由于会话在启动会话后(在我们的例子中:您的默认- type-Session) 您不能再修改当前会话的配置对象。因此,如果您的设计不允许将新任务与新的(希望) BG-type-Session 关联,则无法仅将“dataTask”神奇地转换为“downloadTask”。
请记住,NSURLSessionDataTask 和 NSURLSessionDownloadTask 都是 NSURLSessionTask 的子类,NSURLSessionDataTask 和 NSURLSessionDownloadTask 处理传入的响应数据 (分别是分段 VS 文件) 由框架实现的非常不同。
一个吸引人的错觉可以是这个吸引人的方法URLSession:dataTask:didBecomeDownloadTask:
,但是你必须创建一个与当前相关联的新任务(实际上是DownloadTask)(深深地印在你之前配置的默认值上- type) 会话,并将原始任务 (dataTask) 保留为孤立任务。我的理解是,由于任务的额外创建,您的设计不能采用此选项,并且您将不得不保留默认类型的会话配置。
URLSession:dataTask:didBecomeDownloadTask: 应该真正命名为 URLSession:dataTask:wasReplacedByDownloadTask:
我现在唯一简单的解决方案是,在 Data-Task-Delegate (类实现 NSURLSessionDataDelegate 协议) 中,当接收 URLSession:dataTask:didReceiveData: 初始调用时,开始将这些分段数据存储在以某种方式(存储到临时文件中,也许,模拟 NSURLSessionDownloadTask 的默认操作),并确保 在 NSOperationQueue 上异步执行此委托 (我猜你“后台能力”是指辅助线程,可以由 NSOperationQueue 下划线线程机制提供),直到下载完成,然后检查您的存储是否有累积的结果(如果处理任何错误和/或将文件转移到其他地方) 在这个通用的 NSURLSessionTaskDelegate 方法“URLSession:task:didCompleteWithError:”中
这样做,您将请求(由 NSURLSessionDataTask 表示)转换为下载(不是 NSURLSessionDownloadTask)。为了满足在后台队列上发生的这种转换,请为此委托方法的最后一个参数(会话/任务)提供一个非零值:--否则,串行操作队列将无法满足您的“后台能力”需求
NSOperationQueue* aQueue = [[NSOperationQueue alloc] init];
NSURLSession *sessione = [NSURLSession sessionWithConfiguration:configuratione delegate:self delegateQueue: aQueue];
其他想法是手动执行多个 NSOperation-objects,覆盖它们的 start-methods 以确保您的下载任务异步执行,这可能有点棘手。
任何其他有更好解决方案的人,请带来更多火花......或纠正我可能造成的任何误导。
【讨论】:
但是您的解决方案与后台配置完全不同,后台配置在操作系统管理的进程中进行下载,即使应用程序在后台并被操作系统杀死,它也会继续。 我们可以说下载任务比数据任务强大吗?因为它允许 (1) 在应用程序连续启动时恢复下载。 (2) 即使应用程序未处于活动状态,也可以继续下载,对用户有吸引力。以上是关于将 NSURLSessionDataTask 转换为具有后台支持的下载任务的主要内容,如果未能解决你的问题,请参考以下文章
如何将“C++ 完成处理程序”传递给 NSURLSessionDataTask 以处理它返回的数据?
NSURLSessionDataTask 导致高 CPU 使用率
如何获取数据以从 NSURLSessionDataTask 返回
appdelegate 中的 NSURLSessionDataTask