使用NSURLSessionDownloadTask设置并发下载的数量

Cor*_*eke 25 ios ios7 nsurlsession

我正在使用新的NSURLSession API并允许用户下载文件.我想尝试告诉我的NSURLSession要同时运行多少次下载,但我没有办法做到这一点.我想尽量避免自己管理下载任务,如果我可以告诉系统有多少允许,那会更好 - 这对于排队后台下载以及我的应用程序未运行时会更好.有没有办法做到这一点?

Cou*_*per 19

您可以NSURLSessionConfiguration使用HTTPMaximumConnectionsPerHost属性在对象中设置它.

  • 因此,虽然这确实有效,但系统仍然不会像我想要的那样排队下载.如果我将max设置为3并选择5个下载开始,则最后2个将最终超时而前两个运行.有没有办法让系统排队下载? (8认同)
  • 在NSURLSessionConfiguration中,您可以设置*两个*超时:一个是指定您等待整个资源完成所接受的最长持续时间:`timeoutIntervalForResource` - 另一个与网络丢失有关:`timeoutIntervalForRequest`,仅在以下时触发基础网络在该期间内不再接收任何*新*数据.您必须将"timeoutIntervalForResource"设置为适当的持续时间,其中包括下载前面的资源所需的时间. (7认同)
  • 这是一个非常愚蠢的设计实现.timeoutIntervalForResource不应包含先前资源下载的时间.如果您不知道有多少先前资源怎么办? (5认同)

kas*_*tus 13

我找到了这个超时的解决方法.

试图在设备上下载具有慢速连接模拟的文件(设置 - >开发人员 - >网络链接调节器 - >选择配置文件 - > 3G - >启用).

这是我的示例代码:

- (void) methodForNSURLSession{
  NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
  _tasksArray = [[NSMutableArray alloc] init];
  sessionConfig.HTTPMaximumConnectionsPerHost = 3;
  sessionConfig.timeoutIntervalForResource = 120;
  sessionConfig.timeoutIntervalForRequest = 120;
  NSURLSession* session = [NSURLSession sessionWithConfiguration:sessionConfig delegate:self delegateQueue:nil];

  // data tasks
  [self createDownloadTasksWithSession:session];

}

- (void) createDownloadTasksWithSession:(NSURLSession *)session{
  for (int i = 0; i < 100; i++) {
    NSURLSessionDownloadTask *sessionDownloadTask = [session downloadTaskWithURL: [NSURL URLWithString:@"https://discussions.apple.com/servlet/JiveServlet/showImage/2-20930244-204399/iPhone%2B5%2BProblem2.jpg"]];
    [_tasksArray addObject:sessionDownloadTask];
    [sessionDownloadTask addObserver:self forKeyPath:@"countOfBytesReceived" options:NSKeyValueObservingOptionOld context:nil];
    [sessionDownloadTask resume];
  }
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
  if([[change objectForKey:@"old"] integerValue] == 0){
    NSLog(@"task %d: started", [_tasksArray indexOfObject: object]);
  }
}

- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error{
    if (!error) {
      NSLog(@"task %d: finished!", [_tasksArray indexOfObject:task]);
    } else if (error.code == NSURLErrorTimedOut) {
      NSLog(@"task %d: timed out!", [_tasksArray indexOfObject:task]);
    }
}
Run Code Online (Sandbox Code Playgroud)

我的输出:

2014-01-10 10:38:48.769 TestApplication[2442:1803] task 1: started
2014-01-10 10:38:49.517 TestApplication[2442:1803] task 2: started
2014-01-10 10:38:50.273 TestApplication[2442:4b03] task 0: started
2014-01-10 10:40:11.794 TestApplication[2442:5003] task 2: finished!
2014-01-10 10:40:13.924 TestApplication[2442:1803] task 3: started
2014-01-10 10:40:26.221 TestApplication[2442:1d0f] task 1: finished!
2014-01-10 10:40:28.487 TestApplication[2442:1d0f] task 4: started
2014-01-10 10:40:43.007 TestApplication[2442:440f] task 5: timed out!
2014-01-10 10:40:43.009 TestApplication[2442:440f] task 6: timed out!
2014-01-10 10:40:43.011 TestApplication[2442:440f] task 7: timed out!
...
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,任务在2分钟后开始超时

我玩了timeoutIntervalForResource和timeoutIntervalForRequest参数,如果我们将它们都设置为0,它将下载而不会超时.但我觉得这不是一个好主意,因为电池已经被吸引了.我认为10分钟或类似的东西对它来说是一个很好的价值.但是您必须将两个参数都设置为相同的值.

Apple文档:

timeoutIntervalForRequest - 等待其他数据时使用的超时间隔.timeoutIntervalForResource - 应允许资源请求的最长时间(所有任务超时到一个资源)

注意到奇怪的事情:在情况下,我们设置timeoutIntervalForResource = 60timeoutIntervalForRequest = 30,30秒后的任务会超时!但他们中的大多数甚至都不会开始!

看起来像计时器timeoutIntervalForRequest在任务恢复时启动.在这种情况下,我们在同一时间恢复所有任务,每个任务的超时必须是资源超时.

另外,我可以通过一个关于下载任务的后台会话的精彩演示来建议wwdc13 705会话.

  • 文档说每次接收数据时都会重置timeoutIntervalForRequest - 因此只要继续在数据中流入,该连接就会保持活动状态.但是,timeoutIntervalForResource是请求的TOTAL超时.DOCS:"资源计时器在请求启动时启动并计数,直到请求完成或达到此超时间隔,以先到者为准." 请求的默认值为60秒,资源的默认值为7天. (2认同)