Reputation: 236
I've noticed that it's possible for an NSManagedObjectContext
with an NSMainQueueConcurrencyType
to performBlockAndWait
: and execute the block on a queue other than the receiver's (main) queue.
For example, the following code results in my parentContext
executing the block on the childContext
's queue if my parentContext
is of type NSMainQueueConcurrencyType
and my childContext
is of type NSPrivateQueueConcurrencyType
:
[childContext performBlockAndWait:^{
//Thread 1, Queue: NSManagedObjectContext Queue
[parentContext performBlockAndWait:^{
//Thread 1, Queue: NSManagedObjectContext Queue
//This is the same queue as the child context's queue
}];
}];
In contrast, the following code works as expected – my parentContext
executes the block on the main queue:
[childContext performBlock:^{
[parentContext performBlockAndWait:^{
//Thread 1, Queue: com.apple.main-thread
}];
}];
Is this the expected behavior? It is certainly confusing me since the docs state "performBlockAndWait: synchronously performs a given block on the receiver’s queue."
Upvotes: 4
Views: 922
Reputation: 57040
You should not be worried on what thread blocks are executed. What the performBlock:
and performBlockAndWait:
methods guarantee is thread safety. Thus, calling performBlockAndWait:
from the main thread does not mean there would be a context switch to a background thread - it is very expensive and it is not needed. If during the operation of the block (on the main thread), an attempt is performed to perform a block, it would be blocked until the currently executing block is finished. At the end of the day, the result would be the same as if a context switch was performed, only faster. On the other hand, calling performBlock:
will queue the block on an arbitrary queue, often executing on a background thread.
In the example above, since you performBlockAndWait:
, your private queue context executes your block on the main thread, as does the main context block. In your second example, you schedule the block to run asynchronously, so it is executed on a background thread.
You should not judge a thread's queue by it's name. To see if you are on the main queue, you can use dispatch_get_current_queue()
and test if it is equal to dispatch_get_main_queue()
.
Upvotes: 3