【问题标题】:NSURLSessionDownloadTask keeps retrying when using Background ConfigurationNSURLSessionDownloadTask 在使用后台配置时不断重试
【发布时间】:2014-10-15 09:50:20
【问题描述】:

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

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 上找到了这个link about timeout issue for background session。它已经 10 个月大了,但没有解决方案,只有人们同意。

【问题讨论】:

    标签: objective-c background timeout nsurlsession nsurlsessionconfiguration


    【解决方案1】:

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

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

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

    来源:Apple Forum

    【讨论】:

      【解决方案2】:

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

      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];
      

      【讨论】:

      • 非常好,易读,谢谢!虽然我的代码 sn-p 实际上分布在两个单独的类上,但我会应用我能从中得到的:)
      【解决方案3】:

      我设法解决了。我并不是说我的解决方案是 解决方案,而是 a 解决方案。

      我遇到的行为是 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 answer 以获得更好的代码质量。但是,我的代码 sn-p 分布在不同的类中,因此我无法 100 % 重用该方法。

      【讨论】:

      • 问题:你到底为什么要区分 iOS 8 和 iOS 7?你不能同时设置 timeoutIntervalForRequest 和 timeoutInterval 吗?
      【解决方案4】:

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-06-10
        • 2015-03-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多