使用后台配置时,NSURLSessionDownloadTask会继续重试

Nic*_*son 7 timeout background objective-c nsurlsession nsurlsessionconfiguration

我遇到了一个问题,那就是后端速度慢,后台配置下载数据.

NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration backgroundSessionConfiguration:identifier];
_backgroundSession = [NSURLSession sessionWithConfiguration:sessionConfig delegate:self delegateQueue:nil];
NSURLSessionDownloadTask *downloadTask = [_backgroundSession downloadTaskWithURL:URL];
[downloadTask resume];
Run Code Online (Sandbox Code Playgroud)

如果连接已建立,但发送回数据需要超过60秒,则会发生超时.那样就好.然而,我遇到的行为是我没有得到错误.会话只发出一个新请求."再次给我数据".我不知道发生了什么.不在我的代码中,也没有调用我知道的委托方法.我只能访问服务器日志.它需要服务器大约68秒才能发回数据,但应用程序只是忽略它,因为它正在等待新请求.

一种解决方案是增加超时值.但我不喜欢它,它只适用于iOS 7.不是iOS 8.

sessionConfig.timeoutIntervalForRequest = 10 * 60.0;
Run Code Online (Sandbox Code Playgroud)

有没有人对此有任何见解?我在stackoverflow上找到了关于后台会话超时问题的链接.这是10个月大,但没有解决方案,只有人同意.

Uts*_*sad 7

从iOS8开始,如果服务器没有响应,则后台模式下的NSUrlSession不会调用此委托方法.-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error 下载/上传无限期保持空闲状态.当服务器没有响应时,在iOS7上调用此委托时出错.

通常,如果线路出现问题,NSURLSession后台会话不会使任务失败.相反,它继续寻找运行请求并在那时重试的好时机.这将一直持续到资源超时到期(即,用于创建会话的NSURLSessionConfiguration对象中的timeoutIntervalForResource属性的值).该值的当前默认值为一周!换句话说,iOS7中超时失败的行为是不正确的.在后台会话的上下文中,由于网络问题而不立即失败更有趣.因此,自iOS8以来,NSURLSession任务即使遇到超时和网络丢失也会继续.然而,它会一直持续到达timeoutIntervalForResource.

所以基本上timeoutIntervalForRequest在后台会话中不起作用,但是timeoutIntervalForResource会起作用.

来源:Apple论坛


Sun*_*kas 6

无法阻止自己,这是你的答案有点重构:)

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
NSURLSessionConfiguration *sessionConfig;
float timeout = 5 * 60.0f;

BOOL iOS8OrNewer = [[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0;
if (iOS8OrNewer) {
    sessionConfig = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:identifier];
    request.timeoutInterval = timeout;
}
else {
    sessionConfig = [NSURLSessionConfiguration backgroundSessionConfiguration:identifier];
    sessionConfig.timeoutIntervalForRequest = timeout;
}

_backgroundSession = [NSURLSession sessionWithConfiguration:sessionConfig delegate:self delegateQueue:nil];

NSURLSessionDownloadTask *downloadTask = [_backgroundSession downloadTaskWithRequest:request];
Run Code Online (Sandbox Code Playgroud)

  • 非常好,易读,谢谢!虽然我的代码片段实际上是分散在两个单独的类中,但我会应用它可以从中:) (2认同)

Nic*_*son 3

我设法解决了它。我并不是说我的解决方案就是解决方案,但它确实是解决方案。

我遇到的情况是 iOS 7 和 iOS 8 对属性的优先级不同。我有两个地方可以设置这些超时属性:NSURLSessionConfigurationNSMutableURLRequest。iOS 7 不太关心 requests 属性,iOS 8 也不太关心配置属性。现在我的解决方案如下所示:

NSURLSessionConfiguration *sessionConfig;
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0) {
    sessionConfig = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:identifier];
}
else {
    sessionConfig = [NSURLSessionConfiguration backgroundSessionConfiguration:identifier];
}
if ([[[UIDevice currentDevice] systemVersion] floatValue] < 8.0) {
    sessionConfig.timeoutIntervalForRequest = 5 * 60.0;
}
_backgroundSession = [NSURLSession sessionWithConfiguration:sessionConfig delegate:self delegateQueue:nil];

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0) {
    request.timeoutInterval = 5 * 60.0;
}
NSURLSessionDownloadTask *downloadTask = [_backgroundSession downloadTaskWithRequest:request];
Run Code Online (Sandbox Code Playgroud)

我想人们可以不进行系统版本检查并将这两个属性设置为相同的值。尽管我坚信代码越少越好,但我更坚信不影响不需要受影响的状态。不过我很想听听人们的意见。如果有人有更好的解决方案请分享

哦,还有一件事。根据文档,重试部分将持续发生,直到 timeoutIntervalForResource 达到默认值 7 天。我已将其缩短至 10 分钟。

sessionConfig.timeoutIntervalForResource = 10 * 60;
Run Code Online (Sandbox Code Playgroud)

我并不是说应该改变它。这是我们针对特定环境设置做出的决定。

更新

我们将 timeoutIntervalForResource 更改回默认值 7 天。例如,我们在中国有客户,其中一些客户的网络连接非常差。10 分钟的大师限制实在是太愚蠢了。

请务必查看Sunkas 答案以获得更好的代码质量。然而,我的代码片段分布在不同的类中,因此我无法 100% 重用该方法。