I've used both GCD and performSelectorOnMainThread:waitUntilDone in my apps, and tend to think of them as interchangeable–that is, performSelectorOnMainThread:waitUntilDone is an Obj-C wrapper to the GCD C syntax. I've been thinking of these two commands as equivalent:
dispatch_sync(dispatch_get_main_queue(), ^{ [self doit:YES]; });
[self performSelectorOnMainThread:@selector(doit:) withObject:YES waitUntilDone:YES];
Am I incorrect? That is, is there a difference of the performSelector* commands versus the GCD ones? I've read a lot of documentation on them, but have yet to see a definitive answer.
Best Answer
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 ondispatch_sync
, we see:where for
-performSelectorOnMainThread:
we seeI 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:
Update: In response to Dave Dribin pointing out the caveats section on
dispatch_get_current_queue()
, I've changed to using[NSThread isMainThread]
in the above code.I then use
to perform the actions I need to secure on the main thread, without worrying about what thread the original method was executed on.