So I'm creating my download on the main thread
NSURLRequest *request = [NSURLRequest requestWithURL:download.URL];
NSURLSessionDownloadTask *downloadTask = [self.downloadSession downloadTaskWithRequest:request];
[downloadTask resume];
and adding the NSManagedContextID associated with the download to an NSMutableDictionary, so I can retrieve it later in the delegate call-backs
[self.downloads setObject:[download objectID] forKey:[NSNumber numberWithInteger:downloadTask.taskIdentifier]];
My self.downloadSession
above is configured like this
- (NSURLSession *)backgroundSession
{
static NSURLSession *session = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration backgroundSessionConfiguration:@"com.test.backgroundSession"];
configuration.discretionary = YES;
session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];
});
return session;
}
My problem is the delegate callbacks seem to be called on different threads
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
{
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];
}
So when I access self.downloads to get the correct objectID, I'm actually accessing the NSMutableDictionary from a different thread than the one it was created on, and I believe NSMutableDictionary isn't thread safe. So what is the best solution for this, I could used something like this
session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:[NSOperationQueue mainQueue]];
when declaring the session, set the delegate queue to the mainQueue which causes all the delegates to be called on the main thread, but I would like to keep all the callbacks on a background thread if possible