iPhone - Grand Central Dispatch main thread
Asked Answered
H

6

146

I have been using with success, grand central dispatch in my apps, but I was wondering what is the real advantage of using something like this:

dispatch_async(dispatch_get_main_queue(), ^{ ... do stuff

or even

dispatch_sync(dispatch_get_main_queue(), ^{ ... do stuff

I mean, in both cases you are firing a block to be executed on the main thread, exactly where the app runs and this will not help to reduce the load. In the first case you don't have any control when the block will run. I have seen cases of blocks being executed half a second after you fire them. The second case, it is similar to

[self doStuff];

right?

I wonder what do you guys think.

Harslet answered 26/10, 2011 at 15:42 Comment(3)
By the way, throwing a main queue into a dispatch_sync will result in a deadlock.Koller
Just read it in docs: "Unlike dispatch_async, [dispatch_sync] does not return until the block has finished. Calling this function and targeting the current queue results in deadlock."... But perhaps I'm reading this wrong... (the current queue does not mean main thread). Please correct if I am wrong.Koller
@BrooksHanes not always true. It will result a deadlock if you are already on the main thread. If not then there wouldn't be a deadlock. See hereHelminthology
B
296

Dispatching a block to the main queue is usually done from a background queue to signal that some background processing has finished e.g.

- (void)doCalculation
{
    //you can use any string instead "com.mycompany.myqueue"
    dispatch_queue_t backgroundQueue = dispatch_queue_create("com.mycompany.myqueue", 0);

    dispatch_async(backgroundQueue, ^{
        int result = <some really long calculation that takes seconds to complete>;

        dispatch_async(dispatch_get_main_queue(), ^{
            [self updateMyUIWithResult:result];
        });    
    });
}

In this case, we are doing a lengthy calculation on a background queue and need to update our UI when the calculation is complete. Updating UI normally has to be done from the main queue so we 'signal' back to the main queue using a second nested dispatch_async.

There are probably other examples where you might want to dispatch back to the main queue but it is generally done in this way i.e. nested from within a block dispatched to a background queue.

  • background processing finished -> update UI
  • chunk of data processed on background queue -> signal main queue to start next chunk
  • incoming network data on background queue -> signal main queue that message has arrived
  • etc etc

As to why you might want to dispatch to the main queue from the main queue... Well, you generally wouldn't although conceivably you might do it to schedule some work to do the next time around the run loop.

Buckboard answered 26/10, 2011 at 16:6 Comment(8)
Ah, I see. So, I am right. There's no advantage in doing that if you are already on the main queue, just if you are on another queue and want to update the UI. Thanks.Harslet
Just edited my answer to talk about why it's not very useful to do this from the main queue.Buckboard
Also, I think there's a bug in iOS 4 (might have gone in iOS 5), where dispatch_sync to the main queue from the main thread just causes a hang, so I would avoid doing that entirely.Shamus
That's not a bug, that's the expected behaviour. Not very useful behaviour admittedly but you always need to be aware of deadlocks when using dispatch_sync. You can't expect the system to protect you from programmer error all the time.Buckboard
What is backgroundQueue here? How do I create backgroundQueue objectSelfdrive
@NileshTupe just check the updated answer please!, btw already Robin has described it in great way! +1 for this.Phosphorism
i dont understand something here.. so the first call to the background queue initiates this lengthy calculation. But since it is called asynchronously, doesn't that mean that the nested call to dispatch on main queue could begin before the calculation is complete?Congo
In your answer, where have discussed what is dispatch_sync(dispatch_get_main_queue() and where it should or shouldn't be used? You only wrote about the async kind...Helminthology
S
17

Dispatching blocks to the main queue from the main thread can be useful. It gives the main queue a chance to handle other blocks that have been queued so that you're not simply blocking everything else from executing.

For example you could write an essentially single threaded server that nonetheless handles many concurrent connections. As long as no individual block in the queue takes too long the server stays responsive to new requests.

If your program does nothing but spend its whole life responding to events then this can be quite natural. You just set up your event handlers to run on the main queue and then call dispatch_main(), and you may not need to worry about thread safety at all.

Sacking answered 11/4, 2012 at 19:51 Comment(0)
I
11

Hopefully I'm understanding your question correctly in that you are wondering about the differences between dispatch_async and dispatch_sync?

dispatch_async

will dispatch the block to a queue asynchronously. Meaning it will send the block to the queue and not wait for it to return before continuing on the execution of the remaining code in your method.

dispatch_sync

will dispatch the block to a queue synchronously. This will prevent any more execution of remaining code in the method until the block has finished executing.

I've mostly used a dispatch_async to a background queue to get work off the main queue and take advantage of any extra cores that the device may have. Then dispatch_async to the main thread if I need to update the UI.

Good luck

Ideography answered 26/10, 2011 at 16:24 Comment(1)
thanks, but I am asking about the advantages from sending something to the main queue, being on the main queue.Harslet
T
9

One place where it's useful is for UI activities, like setting a spinner before a lengthy operation:

- (void) handleDoSomethingButton{

    [mySpinner startAnimating];

    (do something lengthy)
    [mySpinner stopAnimating];
}

will not work, because you are blocking the main thread during your lengthy thing and not letting UIKit actually start the spinner.

- (void) handleDoSomethingButton{
     [mySpinner startAnimating];

     dispatch_async (dispatch_get_main_queue(), ^{
          (do something lengthy)
          [mySpinner stopAnimating];
    });
}

will return control to the run loop, which will schedule UI updating, starting the spinner, then will get the next thing off the dispatch queue, which is your actual processing. When your processing is done, the animation stop is called, and you return to the run loop, where the UI then gets updated with the stop.

Tanto answered 10/7, 2014 at 2:48 Comment(2)
@Jerceratops yes but it allows the current runloop to complete.Emend
Yes, but it's still terrible. It still blocks the UI. I might press another button right after this one. Or try and scroll. "(do something lengthy)" should not happen on the main thread, and dispatch_async to let the button click "finish" is not an acceptable solution.Dumont
P
8

Swift 3, 4 & 5

Running code on the main thread

DispatchQueue.main.async {
    // Your code here
}
Premeditate answered 16/2, 2018 at 12:23 Comment(0)
W
0

Async means asynchronous and you should use that most of the time. You should never call sync on main thread cause it will lock up your UI until the task is completed. You Here is a better way to do this in Swift:

runThisInMainThread { () -> Void in
    // Run your code like this:
    self.doStuff()
}

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

Wesleyanism answered 6/12, 2015 at 3:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.