Does Dispatch_Async(Dispatch_Get_Main_Queue(), ^{...}); Wait Until Done

Does dispatch_async(dispatch_get_main_queue(), ^{...}); wait until done?

No it doesn't wait and the way you are doing it in that sample is not good practice.

dispatch_async is always asynchronous. It's just that you are enqueueing all the UI blocks to the same queue so the different blocks will run in sequence but parallel with your data processing code.

If you want the update to wait you can use dispatch_sync instead.

// This will wait to finish
dispatch_sync(dispatch_get_main_queue(), ^{
// Update the UI on the main thread.
});

Another approach would be to nest enqueueing the block. I wouldn't recommend it for multiple levels though.

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Background work

dispatch_async(dispatch_get_main_queue(), ^{
// Update UI

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Background work

dispatch_async(dispatch_get_main_queue(), ^{
// Update UI
});
});
});
});

If you need the UI updated to wait then you should use the synchronous versions. It's quite okay to have a background thread wait for the main thread. UI updates should be very quick.

Why does the block after dispatch_async(dispatch_get_main_queue() never get called?

That is because your TestClass object is released as soon as the main() function exits. Being mainly async, the testMethod: does not block the pointer in the main().

Try adding a semaphore at the end of the main(). This semaphore should be signaled in the testMethod dispatch_async(dispatch_get_main_queue(), ^{}); block.

Where do I need to use dispatch_async on main_queue?


  1. dispatch_get_main_queue() function will return the main queue where your UI is running.
  2. The dispatch_get_main_queue() function is very useful for updating the iOS app’s UI as UIKit methods are not thread safe (with a few exceptions) so any calls you make to update UI elements must always be done from the main queue.

for more see this link

https://www.hackingwithswift.com/read/9/4/back-to-the-main-thread-dispatch_get_main_queue

Wait for an async methods to finish in a for loop

One GCD approach is to use dispatch_group. So, before you start an asynchronous task, call dispatch_group_enter, and then when the asynchronous task finishes, call dispatch_group_leave, and you can then create a dispatch_group_notify which will be called when the asynchronous tasks finish. You can marry this with a completion block pattern (which is a good idea for asynchronous methods, anyway):

  1. If getInformations, getExperiences and getEducation are, themselves, all asynchronous methods, the first thing you need is some mechanism to know when they're done. A common solution is to implement a completion block pattern for each. For example:

    // added completionHandler parameter which will be called when the retrieval
    // of the "informations" is done.

    - (void)getInformations:(User*)user completionHandler:(void (^)(void))completionHandler {
    // do whatever you were before, but in the asynchronous task's completion block, call this
    // completionHandler()
    //
    // for example

    NSURLRequest *request;

    [NSURLConnection sendAsynchronousRequest:request queue:nil completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
    // handle the request here

    // the important thing is that the completion handler should
    // be called _inside_ the this block

    if (completionHandler) {
    completionHandler();
    }
    }];
    }

    Repeat this process for getExperiences and getEducation, too.

  2. Then, you can use a dispatch group to notify you of when each of these three requests are done done, calling a completion block in getUserInfo when that takes place:

    // added completion handler that will be called only when `getInformations`,
    // `getExperiences` and `getEducation` are all done.
    //
    // this takes advantage of the completion block we added to those three
    // methods above

    - (void)getUserInfo:(User*)user completionHandler:(void (^)(void))completionHandler {
    dispatch_group_t group = dispatch_group_create();

    // start the three requests

    dispatch_group_enter(group);
    [self getInformations:user completionHandler:^{
    dispatch_group_leave(group);
    }];

    dispatch_group_enter(group);
    [self getExperiences:user completionHandler:^{
    dispatch_group_leave(group);
    }];

    dispatch_group_enter(group);
    [self getEducation:user completionHandler:^{
    dispatch_group_leave(group);
    }];

    // this block will be called asynchronously only when the above three are done

    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
    if (completionHandler) {
    completionHandler();
    }
    });
    }
  3. And you then repeat this process at the getAllUsersInformations:

    // call new getUserInfo, using dispatch group to keep track of whether
    // all the requests are done

    -(void)getAllUsersInformations {

    dispatch_group_t group = dispatch_group_create();

    for(User *user in users){
    dispatch_group_enter(group);

    [self getUserInfo:user completionHandler:^{
    dispatch_group_leave(group);
    }];
    }

    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
    [self.tableView reloadData];
    });
    }

Two final thoughts:

  1. Having outlined all of that, I must confess that I would probably wrap these requests in concurrent/asynchronous custom NSOperation subclasses instead of using dispatch groups. See the "Configuring Operations for Concurrent Execution" section of the Concurrency Programming Guide. This is a more radical refactoring of the code, so I won't tackle that here, but it lets you constrain the number of these requests that will run concurrently, mitigating potential timeout issues.

  2. I don't know how many of these user requests are going on, but you might want to consider updating the UI as user information comes in, rather than waiting for everything to finish. This is, again, a more radical refactoring of the code, but might lead to something that feels more responsive.

dispatch_async on main_queue?

I lost track of this question, but as it still gets traction, I'll post an answer to this (using swift)

Assumptions: I do know that UI work has to be done on the main thread.

//
// We are on the main thread here.
// The following will schedule the closure on the main thread after ALL other
// routines currently scheduled on the main thread are done.
//
DispatchQueue.main.async {
//
// So here we are back on the main thread AFTER all routines on the main
// thread have completed.
//
// If the following call does NOT dispatch onto a background thread
// it will block the UI and it was really bad programming.
//
// Thus, for now and for the benefit of the doubt, let's assume
// `doSomeNetworkStuff()` DOES dispatch to a background thread.
//
// This can only make sense if the the func `doSomeNetworkStuff()`
// relies on results of code paths following this current
// `DispatchQueue.main.async(... we are here ...)`.
//
// If `doSomeNetworkStuff()` does NOT depend on any other code paths:
// Why not directly scheduling it directly on a background thread?
// Which is unnecessary, as as stated above it MUST dispatch on to the
// background anyways.
//
// Moreover, there is few possibility that `doSomeNetworkStuff()` does
// depend on other codepaths, because `self` is already captured by
// the closure.
//
self.doSomeNetworkStuff()
}

Taking all this together IMHO the original code does not make very much sense. It could be replaced with:

// We are on the main thread here
self.doSomeNetworkStuff()

The original async dispatch onto the main thread to then dispatch to background should be wasteful and confusing (obviously).

Unfortunately I am not in the position anymore to try this out with the original code base.

Am I missing an idea here?

dispatch_async(dispatch_get_main_queue() not firing after NSMutableURLRequest with timeoutInterval

The block is enqueued on the main queue. The main queue is a serial queue, and it will execute the enqueued blocks in order.

If you use a CFRunLoop on the main thread, then the main dispatch queue is drained in that run loop, so if the run loop is occupied with other activity, it will also cause a delay in executing those blocks.

If you don't actually need to do UI or other activities that are serialized on the main thread, you're probably best off not using the main queue.

Wait until dispatch_async thread ends

Canonical answer to such a question: What are you trying to do?

I ask this because, first, you should neither need to know or care that there is a thread backing a GCD request and when it exits - that's entirely up to GCD to manage.

Second, you should always be suspicious of code that uses explicit timeouts (other than "FOREVER"). If you have any reason to ask yourself "Why 1 second? What happens if whatever event I'm waiting for takes more or less time than this?" then you are engaging in the kind of thinking that leads to polling, and polling is just BAD BAD (evil, wrong) design for pretty much everything but writing certain kinds of device drivers!

A far more reasonable approach is to use a completion callback at the end of your operation to signal that it's done, taking a fully async approach to programming and also following, in the process, one of the fundamental design principles of GCD.

It sounds to me, and I'm just guessing here, that you're taking an existing programming paradigm or way of thinking and erroneously applying it to GCD. An understandable mistake, but a mistake nonetheless.



Related Topics



Leave a reply



Submit