问题 将NSURLSessionDataTask转换为具有后台支持的下载任务


在检查标题(对于长度和类型)之后,我需要使用后台才能下载某些文件(不是所有文件),但它必须处于相同的操作中,而不是创建新的任务/请求(因为有时我会得到一个由于短时间内的许多连接而导致服务器出错。 所以我开始任务:

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);
    }
}

但是,由于Data Tasks无法使用BackgroundSessionConfiguration,我认为新创建的下载将使用相同的默认会话配置。 如何在后台运行下载?有没有办法将它的会话改为后台会话?或者哪种方法?


4171
2018-04-25 12:26


起源



答案:


这个问题很难给出一个明确的答案,接缝给我,即所有3个主要的URLLoading因素 (sessionType,taskType,FG / BG创建) 受到您的设计的限制。

由于会话在配置上保留了深层副本 (确定默认/ BackGround / Ephemeral会话 - 自然类型),在开始你的会议后 (在我们的例子中:你的默认类型会话) 你不能再修改当前会话的配置对象了。因此,如果您的设计不允许创建与新关联的新任务 (希望) BG-type-Session,没有办法只将神奇地将“dataTask”转换为“downloadTask”。

记住, NSURLSessionDataTask 和 NSURLSessionDownloadTask 都是。的子类 NSURLSessionTask,NSURLSessionDataTask和NSURLSessionDownloadTask处理传入的响应数据 (分段VS文件分别) 框架实现的方式非常不同。

有吸引力的错觉可能是这种有吸引力的方法 URLSession:dataTask:didBecomeDownloadTask: ,但您必须创建一个新任务 (下载契约中的任务) 与当前相关联 (深受您之前配置的默认类型标记) 会话,并保留原始任务 (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对象,覆盖它们的启动方法以确保下载任务的异步执行,这可能有点棘手。

任何其他有更好解决方案的人,请带来更多火花......或纠正我可能产生的任何误导。


10
2017-07-14 07:48



但是你的解决方案与后台配置完全不同,后台配置在操作系统管理的进程中,即使应用程序处于后台并被操作系统杀死,它也会继续运行。 - Luca Torella
我们可以说下载任务比数据任务强大得多吗?因为它允许 (1) 在连续发布应用程序时继续下载。 (2) 继续下载甚至应用程序不处于活动状态,对用户有吸引力。 - NSPratik


答案:


这个问题很难给出一个明确的答案,接缝给我,即所有3个主要的URLLoading因素 (sessionType,taskType,FG / BG创建) 受到您的设计的限制。

由于会话在配置上保留了深层副本 (确定默认/ BackGround / Ephemeral会话 - 自然类型),在开始你的会议后 (在我们的例子中:你的默认类型会话) 你不能再修改当前会话的配置对象了。因此,如果您的设计不允许创建与新关联的新任务 (希望) BG-type-Session,没有办法只将神奇地将“dataTask”转换为“downloadTask”。

记住, NSURLSessionDataTask 和 NSURLSessionDownloadTask 都是。的子类 NSURLSessionTask,NSURLSessionDataTask和NSURLSessionDownloadTask处理传入的响应数据 (分段VS文件分别) 框架实现的方式非常不同。

有吸引力的错觉可能是这种有吸引力的方法 URLSession:dataTask:didBecomeDownloadTask: ,但您必须创建一个新任务 (下载契约中的任务) 与当前相关联 (深受您之前配置的默认类型标记) 会话,并保留原始任务 (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对象,覆盖它们的启动方法以确保下载任务的异步执行,这可能有点棘手。

任何其他有更好解决方案的人,请带来更多火花......或纠正我可能产生的任何误导。


10
2017-07-14 07:48



但是你的解决方案与后台配置完全不同,后台配置在操作系统管理的进程中,即使应用程序处于后台并被操作系统杀死,它也会继续运行。 - Luca Torella
我们可以说下载任务比数据任务强大得多吗?因为它允许 (1) 在连续发布应用程序时继续下载。 (2) 继续下载甚至应用程序不处于活动状态,对用户有吸引力。 - NSPratik