[objective-c] GCD to perform task in main thread

I have a callback which might come from any thread. When I get this callback, then I would like to perform a certain task on the main thread.

Do I need to check whether I already am on the main thread - or is there any penalty by not performing this check befora calling the code below?

dispatch_async(dispatch_get_main_queue(), ^{
   // do work here
});

This question is related to objective-c grand-central-dispatch

The answer is


As the other answers mentioned, dispatch_async from the main thread is fine.

However, depending on your use case, there is a side effect that you may consider a disadvantage: since the block is scheduled on a queue, it won't execute until control goes back to the run loop, which will have the effect of delaying your block's execution.

For example,

NSLog(@"before dispatch async");
dispatch_async(dispatch_get_main_queue(), ^{
    NSLog(@"inside dispatch async block main thread from main thread");
});
NSLog(@"after dispatch async");

Will print out:

before dispatch async
after dispatch async
inside dispatch async block main thread from main thread

For this reason, if you were expecting the block to execute in-between the outer NSLog's, dispatch_async would not help you.


For the asynchronous dispatch case you describe above, you shouldn't need to check if you're on the main thread. As Bavarious indicates, this will simply be queued up to be run on the main thread.

However, if you attempt to do the above using a dispatch_sync() and your callback is on the main thread, your application will deadlock at that point. I describe this in my answer here, because this behavior surprised me when moving some code from -performSelectorOnMainThread:. As I mention there, I created a helper function:

void runOnMainQueueWithoutDeadlocking(void (^block)(void))
{
    if ([NSThread isMainThread])
    {
        block();
    }
    else
    {
        dispatch_sync(dispatch_get_main_queue(), block);
    }
}

which will run a block synchronously on the main thread if the method you're in isn't currently on the main thread, and just executes the block inline if it is. You can employ syntax like the following to use this:

runOnMainQueueWithoutDeadlocking(^{
    //Do stuff
});

No you don't need to check if you're in the main thread. Here is how you can do this in Swift:

runThisInMainThread { () -> Void in
    runThisInMainThread { () -> Void in
        // No problem
    }
}

func runThisInMainThread(block: dispatch_block_t) {
    dispatch_async(dispatch_get_main_queue(), block)
}

Its included as a standard function in my repo, check it out: https://github.com/goktugyil/EZSwiftExtensions