As Jacob points out, while they may appear the same, they are different things. In fact, there’s a significant difference in the way that they handle sending actions to the main thread if you’re already running on the main thread.
I ran into this recently, where I had a common method that sometimes was run from something on the main thread, sometimes not. In order to protect certain UI updates, I had been using -performSelectorOnMainThread:
for them with no problems.
When I switched over to using dispatch_sync
on the main queue, the application would deadlock whenever this method was run on the main queue. Reading the documentation on dispatch_sync
, we see:
Calling this function and targeting
the current queue results in deadlock.
where for -performSelectorOnMainThread:
we see
wait
A Boolean that specifies whether the
current thread blocks until after the
specified selector is performed on the
receiver on the main thread. Specify
YES to block this thread; otherwise,
specify NO to have this method return
immediately.If the current thread is also the main
thread, and you specify YES for this
parameter, the message is delivered
and processed immediately.
I still prefer the elegance of GCD, the better compile-time checking it provides, and its greater flexibility regarding arguments, etc., so I made this little helper function to prevent deadlocks:
void runOnMainQueueWithoutDeadlocking(void (^block)(void))
{
if ([NSThread isMainThread])
{
block();
}
else
{
dispatch_sync(dispatch_get_main_queue(), block);
}
}
Update: In response to Dave Dribin pointing out the caveats section ondispatch_get_current_queue()
, I’ve changed to using [NSThread isMainThread]
in the above code.
I then use
runOnMainQueueWithoutDeadlocking(^{
//Do stuff
});
to perform the actions I need to secure on the main thread, without worrying about what thread the original method was executed on.