NSURLSession Threads: Tracking multiple background downloads NSURLSession Threads: Tracking multiple background downloads multithreading multithreading

NSURLSession Threads: Tracking multiple background downloads


In your example that is not a problem, since your dictionary is handed over to the notification system and is not used by the operation queue thread again. Thread safety is only a problem when an object is potentially accessed from multiple threads at the same time.

If your dict would be an iVar you should do it this way:

Create your own queue like this

myQueue = [[NSOperationQueue alloc] init];// This creates basically a serial queue, since there is just on operation running at any time.[myQueue setMaxConcurrentOperationCount:1];

Then schedule every Access to your dictionary on this queue, like this for example:

[myQueue addOperationWithBlock:^{    // Access your dictionary }];

And of course use this queue for your URLSesson delegation:

session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:myQueue];

Since this queue is setup as a serial queue, there will always be just one thread accessing the dict in the background.

Take care when you calculate something with the dict information. You have to do this on that queue as well. However, you can put the result of your calculation on any other queue/thread, for example to update the UI on the main thread.

[myQueue addOperationWithBlock:^{    // Calculate with your dictionary    // Maybe the progress calcualtion    NSString* progress = [self calculateProgress: iVarDict];    dispatch_async(dispatch_get_main_queue(), ^    {       // use progress to update UI     });}];

I think for posting a notification you don't have to use that pattern, because the system handles the threading correctly. But to be save you should check this.


You can use a GCD serial queue to ensure only one delegate is executing simultaneously.

You can declare the queue as an instance variable of your class and initialize it in the init method, like this:

dispatch_queue_t delegateQueue;

...

delegateQueue = dispatch_queue_create("com.yourcompany.mydelegatequeue", 0x0);

and in your delegate method, simply make it execute in this queue:

- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{       dispatch_sync(delegateQueue, ^{    NSManagedObjectID *downloadID = [self.downloads objectForKey:[NSNumber numberWithInteger:downloadTask.taskIdentifier]];    double progress = (double)totalBytesWritten / (double)totalBytesExpectedToWrite;    NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:downloadID,@"download",[NSNumber numberWithDouble:progress],@"progress", nil];    [[NSNotificationCenter defaultCenter] postNotificationName:@"DownloadProgress" object:nil userInfo:userInfo];});} 

This way, although every delegate is called in its thread, there is only of them accessing self.downloads at one time, and you can keep them in separate threads.