Waiting Until Two Async Blocks Are Executed Before Starting Another Block

Waiting until two async blocks are executed before starting another block

Use dispatch groups: see here for an example, "Waiting on Groups of Queued Tasks" in the "Dispatch Queues" chapter of Apple's iOS Developer Library's Concurrency Programming Guide

Your example could look something like this:

dispatch_group_t group = dispatch_group_create();

dispatch_group_async(group,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^ {
// block1
NSLog(@"Block1");
[NSThread sleepForTimeInterval:5.0];
NSLog(@"Block1 End");
});


dispatch_group_async(group,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^ {
// block2
NSLog(@"Block2");
[NSThread sleepForTimeInterval:8.0];
NSLog(@"Block2 End");
});

dispatch_group_notify(group,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^ {
// block3
NSLog(@"Block3");
});

// only for non-ARC projects, handled automatically in ARC-enabled projects.
dispatch_release(group);

and could produce output like this:

2012-08-11 16:10:18.049 Dispatch[11858:1e03] Block1
2012-08-11 16:10:18.052 Dispatch[11858:1d03] Block2
2012-08-11 16:10:23.051 Dispatch[11858:1e03] Block1 End
2012-08-11 16:10:26.053 Dispatch[11858:1d03] Block2 End
2012-08-11 16:10:26.054 Dispatch[11858:1d03] Block3

Waiting until the task finishes

Use DispatchGroups to achieve this. You can either get notified when the group's enter() and leave() calls are balanced:

func myFunction() {
var a: Int?

let group = DispatchGroup()
group.enter()

DispatchQueue.main.async {
a = 1
group.leave()
}

// does not wait. But the code in notify() gets run
// after enter() and leave() calls are balanced

group.notify(queue: .main) {
print(a)
}
}

or you can wait:

func myFunction() {
var a: Int?

let group = DispatchGroup()
group.enter()

// avoid deadlocks by not using .main queue here
DispatchQueue.global(attributes: .qosDefault).async {
a = 1
group.leave()
}

// wait ...
group.wait()

print(a) // you could also `return a` here
}

Note: group.wait() blocks the current queue (probably the main queue in your case), so you have to dispatch.async on another queue (like in the above sample code) to avoid a deadlock.

at point dispatch_group_async considers the task done when it is executing async task with callbacks

If you dispatch an asynchronous task, say "task B", inside a dispatch_group_async, say "Task A" then Task A will be considered complete as soon as the end of the Task A block is reached even though Task B may still be executing.

So, given

dispatch_async_group(group,queue, ^{ 
[someAsyncTask B];
});

dispatch_async_group(group,queue, ^{
[someAsyncTask C];
});

dispatch_async_group(group,queue, ^{
[someAsyncTask D];
});

dispatch_group_wait(group,10000);

The dispatch_group_wait will return as soon as the final dispatch_async_group block finishes executing even though tasks B/C/D may still be running.

If you use synchronous dispatch for tasks B/C/D then your dispatch group will be considered complete after B,C & D finish.

Wait for block of code before running second Swift

Alamofire.request is an asynchronous call so it will return right away and therefore your method getVersion will return right away. You need to make getVersion method wait until Alamofire.request completes the call and versionarray is updated before continuing.

Waiting for asynchronously-executed block to finish

At the point where your NSLog line is run, your completion block has not yet been called. reverseGeocodeLocation is a non-blocking call, which is why it takes a completion handler.

What you DON'T want to do is to turn this into a synchronous method. I presume you want to update your UI in response to the geocode completing. Do something like this:

I don't see what the "[placemarks copy]" line is supposed to achieve. It's completely pointless because you're ignoring the return value.

[deviceInfo.geocoder reverseGeocodeLocation:deviceInfo.locationProperties completionHandler:

^(NSArray *placemarks, NSError *error) {

[placemarks copy];
//Get nearby address
CLPlacemark *placemark = [placemarks objectAtIndex:0];

NSLog(@"Country : %@",placemark.country);
// No need for response to be a __block variable.
NSString *response =placemark.country;
dispatch_async(dispatch_get_main_queue(), ^{
[self updateUIWithResponse:response];
}
];

-(void)updateUIWithResponse:(NSString*)response
{
NSLog(@"Got a response: %@), response);
}


Related Topics



Leave a reply



Submit