Grand Central Dispatch (GCD) vs. performSelector – need a better explanation

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


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

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])
        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

    //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.

Leave a Comment