使用后台配置时,NSURLSessionTask在超时后永远不会回调

Thi*_* D. 20 ios nsurlsession nsurlsessionconfiguration nsurlsessiondownloadtask ios7.1

我正在使用NSURLSessionDownloadTask后台会话来实现我的所有REST请求.这样我可以使用相同的代码,而不必考虑我的应用程序在后台或前台.

我的后端已经死了一段时间了,我借此机会测试了NSURLSession超时的行为方式.

令我惊讶的是,我的NSURLSessionTaskDelegate回调都没有被调用过.无论我在上面NSURLRequest或上面设置什么超时NSURLSessionConfiguration,我都没有从iOS收到任何回调,告诉我请求确实以超时完成.

也就是说,当我开始NSURLSessionDownloadTask一个后台会话时.应用程序在后台或前台发生相同的行为.

示例代码:

- (void)launchDownloadTaskOnBackgroundSession {
    NSString *sessionIdentifier = @"com.mydomain.myapp.mySessionIdentifier";
    NSURLSessionConfiguration *backgroundSessionConfiguration = [NSURLSessionConfiguration backgroundSessionConfiguration:sessionIdentifier];
    backgroundSessionConfiguration.requestCachePolicy = NSURLRequestReloadIgnoringCacheData;
    backgroundSessionConfiguration.timeoutIntervalForRequest = 40;
    backgroundSessionConfiguration.timeoutIntervalForResource = 65;
    NSURLSession *backgroundSession = [NSURLSession sessionWithConfiguration:backgroundSessionConfiguration delegate:self delegateQueue:[NSOperationQueue mainQueue]];

    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://www.timeout.com/"]];
    request.timeoutInterval = 30;
    NSURLSessionDownloadTask *task = [backgroundSession downloadTaskWithRequest:request];
    [task resume];
}

- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
    NSLog(@"URLSession:task:didCompleteWithError: id=%d, error=%@", task.taskIdentifier, error);
}
Run Code Online (Sandbox Code Playgroud)

但是,当我使用默认会话时,我会在30秒后收到错误回调(我在请求级别设置的超时).

示例代码:

- (void)launchDownloadTaskOnDefaultSession {
    NSURLSessionConfiguration *defaultSessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
    defaultSessionConfiguration.requestCachePolicy = NSURLRequestReloadIgnoringCacheData;
    defaultSessionConfiguration.timeoutIntervalForRequest = 40;
    defaultSessionConfiguration.timeoutIntervalForResource = 65;
    NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration:defaultSessionConfiguration delegate:self delegateQueue:[NSOperationQueue mainQueue]];

    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://www.timeout.com/"]];
    request.timeoutInterval = 30;
    NSURLSessionDownloadTask *task = [defaultSession downloadTaskWithRequest:request];
    [task resume];
}

- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
    NSLog(@"URLSession:task:didCompleteWithError: id=%d, error=%@", task.taskIdentifier, error);
}
Run Code Online (Sandbox Code Playgroud)

我似乎无法在文档中找到任何暗示在使用后台会话时超时应该表现不同的内容.

还有人遇到过这个问题吗?这是一个错误还是一个功能?

我正在考虑创建一个错误报告,但我通常会在SO(几分钟)上获得比在bug报告者(六个月)上更快的反馈.

问候,

Uts*_*sad 20

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

通常,如果线路出现问题,NSURLSession后台会话不会使任务失败.相反,它继续寻找运行请求并在那时重试的好时机.这将一直持续到资源超时到期(即,用于创建会话的NSURLSessionConfiguration对象中的timeoutIntervalForResource属性的值).该值的当前默认值为一周!

从此来源获取的引用信息

换句话说,iOS7中超时失败的行为是不正确的.在后台会话的上下文中,由于网络问题而不立即失败更有趣.因此,自iOS8以来,NSURLSession任务即使遇到超时和网络丢失也会继续.然而,它会一直持续到达timeoutIntervalForResource.

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

  • 我从[开发人员论坛](https://forums.developer.apple.com/thread/22690)的Apple员工之一得到了这个答案.另外,我已通过实施验证了这一点. (2认同)
  • 那太棒了,谢谢@ utsav-dusad.欢迎来到Stackoverflow :)总是很高兴提到您的信息来自哪里.在这种情况下,我们只能后悔BackgroundSession文档不完整,因为在我看来这些信息属于那里. (2认同)