3

I am adding multiple tasks to a NSURLSession (background mode) , in an order. I have kept HTTPMaximumConnectionsPerHost = 1. However, I am seeing that the uploads are taken up in a random order i.e, after the 1st item may be 5th item is picked up and then the 3rd item etc - the upload does not happen in the order I had provided to NSURLSession. Is there a way to order the uploads exactly the way it is added?

tuttu47
  • 521
  • 1
  • 4
  • 19
  • you should call next item after finish last item please show your code – Mo Farhand Oct 19 '15 at 13:50
  • I tried chaining uploads. But when the first item finishes and schedules the second upload in background, it starts to upload and then stops abruptly. The second item does not upload in background. – tuttu47 Oct 21 '15 at 10:38

1 Answers1

6

We do not ensure your execution tasks will be executed in order with the configuration of HTTPMaximumConnectionsPerHost = 1 because it just guarantees one task being executed at a time. In term of executing tasks synchronously in order, you can use NSOperationQueue and NSOperation to add the dependency between operations.

NSMutableArray *operations = [NSMutableArray array];
    NSArray *urls = @[];
    NSURLSession *urlSession = [NSURLSession sharedSession];
    for (int i = 0;i < urls.count;i++) {
        NSOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
            NSURLSessionDataTask *task = [urlSession dataTaskWithURL:[NSURL URLWithString:urls[i]] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
            }];
            [task resume];
        }];
        i > 0 ? [operation addDependency:operations[i - 1]] : 0;
        [operations addObject:operation];
    }
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    queue.maxConcurrentOperationCount = 1;
    [queue addOperations:operations waitUntilFinished:YES];

Another solution is use dispatch semaphore of GCD.

dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    NSArray *urls = @[];
    NSURLSession *urlSession = [NSURLSession sharedSession];
    for (NSString *url in urls) {
        NSURLSessionDataTask *task = [urlSession dataTaskWithURL:[NSURL URLWithString:url] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
            dispatch_semaphore_signal(semaphore);                  // signal when done
        }];
        [task resume];
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); // wait for signal before continuing
    }
    //Do s.t after all tasks finished
HSG
  • 1,224
  • 11
  • 17
  • 1
    I tried with NSOperationQueue and it got really messy in background upload mode. As mentioned here:http://stackoverflow.com/questions/21918722/how-do-i-use-nsoperationqueue-with-nsurlsession, I don't think its easy and practical. I also tried chaining uploads, but it stops with the second item abruptly (after some 30 sec, where OS suspends your app on background wake up). – tuttu47 Oct 22 '15 at 14:25
  • @tuttu47 Could you please post your code here, so we can easy to find out the issue. – HSG Oct 23 '15 at 06:54
  • 1
    I have added a detailed description with code here: http://stackoverflow.com/questions/33285179/chaining-background-nsurlsession-uploads – tuttu47 Oct 24 '15 at 08:18