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

时间:2014-10-15 09:50:20

标签: objective-c background timeout nsurlsession nsurlsessionconfiguration

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

NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration backgroundSessionConfiguration:identifier];
_backgroundSession = [NSURLSession sessionWithConfiguration:sessionConfig delegate:self delegateQueue:nil];
NSURLSessionDownloadTask *downloadTask = [_backgroundSession downloadTaskWithURL:URL];
[downloadTask resume];

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

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

sessionConfig.timeoutIntervalForRequest = 10 * 60.0;

有没有人对此有任何见解? 我在stackoverflow上找到了这个link about timeout issue for background session。它已经10个月了,但没有解决方案,只有人同意。

4 个答案:

答案 0 :(得分:7)

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

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

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

来源:Apple Forum

答案 1 :(得分: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];

答案 2 :(得分:3)

我设法解决了这个问题。我不是说我的解决方案是 解决方案,但它是 解决方案。

我遇到的行为是iOS 7和iOS 8优先考虑属性。我有两个地方可以设置这些超时属性, NSURLSessionConfiguration NSMutableURLRequest 。 iOS 7对请求属性的关注度不高,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];

我想有人可能无法进行systemVersion检查并将两个属性设置为相同的值。虽然我坚信更少的代码更多,但我更坚信不会影响那些不需要受影响的国家。但我很想听听人们意见。如果有人有更好的解决方案,请分享

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

sessionConfig.timeoutIntervalForResource = 10 * 60;

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

<强>更新

我们将timeoutIntervalForResource更改回默认值7天。例如,我们在中国有客户,其中一些客户的联系非常糟糕。主要限制为10分钟只是愚蠢。

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

答案 3 :(得分:0)

与服务器对后台上传任务的响应时间过长时发生的重试循环相关的另一个Apple讨论:

https://forums.developer.apple.com/thread/70682