7

当涉及到缓慢的后端和使用后台配置下载数据时,我遇到了问题。

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

如果连接已建立但发送回数据需要超过 60 秒的时间,则会发生超时。那也行。但是我遇到的行为是我没有收到错误。Session 只是发出一个新的请求。“再给我数据”。我不知道这发生在哪里。不在我的代码中,也没有调用我知道的委托方法。我只能访问服务器日志。服务器发送回数据大约需要 68 秒,但应用程序只是忽略它,因为它正在等待新请求。

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

sessionConfig.timeoutIntervalForRequest = 10 * 60.0;

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

4

4 回答 4

8

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

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

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

资料来源:苹果论坛

于 2016-02-12T10:41:19.443 回答
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];
于 2014-10-16T09:49:22.880 回答
3

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

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

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 答案以获得更好的代码质量。但是,我的代码片段分布在不同的类中,因此我无法 100% 重用该方法。

于 2014-10-16T08:59:16.823 回答
0

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

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

于 2018-05-31T22:20:16.543 回答