我遇到了一个问题,当涉及到缓慢的后端和使用后台配置下载数据时。
NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration backgroundSessionConfiguration:identifier];
_backgroundSession = [NSURLSession sessionWithConfiguration:sessionConfig delegate:self delegateQueue:nil];
NSURLSessionDownloadTask *downloadTask = [_backgroundSession downloadTaskWithURL:URL];
[downloadTask resume];
如果连接已重新发布,但发送回数据的时间超过60秒,则会发生超时。那很好。然而,我所经历的行为是,我没有得到错误。Session只是发出一个新的请求。"再给我一次数据"。我不知道这是在哪里发生的。在我的代码中没有,而且据我所知,也没有调用委托方法。我只能访问服务器日志。服务器大约需要68秒才能发送回数据,但应用程序只是忽略了它,因为它正在等待新的请求。
一种解决方案是增加超时值。但我不喜欢它,它只适用于iOS7。不是iOS 8。
sessionConfig.timeoutIntervalForRequest = 10 * 60.0;
有人对此有什么见解吗?我在stackoverflow上找到了这个关于后台会话超时问题的链接。它已经存在了10个月,但没有解决方案,只有人们同意。
由于iOS8,如果服务器没有响应,则后台模式下的NSUrlSession不会调用此委托方法。-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
下载/上传无限期保持空闲。当服务器没有响应时,在iOS7上调用此委托,但出现错误。
通常,如果网络出现问题,NSURLSession后台会话不会使任务失败。相反,它会继续寻找一个好的时间来运行请求,并在那个时候重试。这种情况一直持续到资源超时到期(即用于创建会话的NSURLSessionConfiguration对象中timeoutIntervalForResource属性的值)。该值的当前默认值为一周!换句话说,iOS7中超时失败的行为是不正确的。在后台会话的上下文中,更有趣的是不要因为网络问题而立即失败。因此,自iOS8以来,NSURLSession任务即使遇到超时和网络丢失也会继续。但是,它一直持续到达到timeoutIntervalForResource为止。
所以基本上timeoutIntervalForRequest在后台会话中不起作用,但timeoutInterval ForResource会起作用。
来源:苹果论坛
我无法阻止自己,以下是经过重构的答案:)
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];
我设法解决了它。我并不是说我的解决方案是解决方案,但它是的解决方案。
我所经历的行为是iOS 7和iOS 8对属性的优先级不同。我有两个地方可以设置这些超时属性,NSURLSessionConfiguration和NSFmutableURLRequest。iOS 7非常关心requests属性,iOS 8也非常关心configurations属性。现在我的解决方案是这样的:
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%重用这种方法。
另一个与服务器对后台上传任务的响应耗时过长时发生的重试循环有关的苹果讨论:
https://forums.developer.apple.com/thread/70682