Search code examples
iosmultithreadingnsurlsessionnsoperationcfrunloop

Using Runloop in inside nsoperation for async tasks


I have a use case where I need to download many files using NSURLSession.

To keep the sessiontasks from timing out I need to place them in an operation queue and limit the amount of concurrent downloads so they don't starve.

My idea is that I will load the task resume into an nsoperation and load them into an nsoperationqueue that will limit the number of concurrent activitiy.

The issue is that when I call [task resume] the code will exit and the nsoperation will consider itself complete even though I am waiting for the file to finish downloading.

Here is some code.

NSURLSessionDownloadTask *task = [session downloadTaskWithRequest: request 
completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {

     //move the file to a permanent location

     CFRunLoopStop(CFRunLoopGetCurrent());
}
//I have instantiated a class global NSOperation queue.
[imageDownloadQueue addOperationWithBlock:^void() {
     [task resume];
     CFRunLoopRun();
}];

How can I keep the nsoperation thread alive while I wait for the callback? I have also tried using nsrunloop and adding a port to NSMachPort. That didn't seem to help.

Also, setting the HttpMaximumConnectionsPerHost on the NSURLSession doesn't help because the timeout timer starts when I resume a task. Which means I will get more timeouts than before.


Solution

  • Sadly, I didn't have time for a proper fix and I needed the timeout issues fixed ASAP. I found something that did work.

        //I have instantiated a class global NSOperation queue.
    [imageDownloadQueue addOperationWithBlock:^void() {
         [task resume];
         while(task.state == NSURLSessionTaskStateRunning)
        {
             [NSThread sleepForTimeInterval:.1];
        }
        }];
    

    Since the NSOperation works on a background thread, I was able to sleep that thread while the task is running. This keeps the thread from dying but the task will run on it's own thread and isn't blocked.