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.