Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Set number of concurrent downloads with NSURLSessionDownloadTask

I'm using the new NSURLSession API and allowing the user to download files. I'd like to try and tell my NSURLSession how many simultaneous downloads to run, but I don't see a way to do it. I'd like to try to avoid managing the download tasks myself, would be much better if I could tell the system how many to allow instead - that would be better for queuing background downloads as well when my app isn't running. Is there a way to do this?

like image 477
Cory Imdieke Avatar asked Jan 02 '14 17:01

Cory Imdieke


2 Answers

You can set it in the NSURLSessionConfiguration object with the HTTPMaximumConnectionsPerHost property.

like image 104
CouchDeveloper Avatar answered Nov 04 '22 10:11

CouchDeveloper


I found a workaround for this timeouts.

Tried to download a file with slow connection simulation on device(Settings -> Developer -> Network link conditioner -> Choose a profile -> 3G -> Enable).

Here is my sample code:

- (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]);
    }
}

And my output:

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!
...

As you can see tasks started time out after 2 minutes

I played with timeoutIntervalForResource and timeoutIntervalForRequest parameters and in case we set both to 0 it will downloads without timeouts. But I think it isn't a good idea because of battery drawn. I think that 10 minutes or something like it will be a good value for it. But you have to set both parameters to the same value.

Apple docs:

timeoutIntervalForRequest - The timeout interval to use when waiting for additional data. timeoutIntervalForResource - The maximum amount of time that a resource request should be allowed to take.(timeout for all tasks to one resource)

Noticed strange thing: in case we set timeoutIntervalForResource = 60 and timeoutIntervalForRequest = 30, tasks will time out after 30 seconds! But most of them won't even start!

Looks like timer for timeoutIntervalForRequest started when task resumed. In that case we resumed all tasks in the same time and each task's timeout has to be as a resource timeout.

Also, I can advise wwdc13 705 session with a great demo about background session with download task.

like image 15
kaspartus Avatar answered Nov 04 '22 11:11

kaspartus