Sometimes we face the following problem:
We have two tasks (or blocks) and we get errors because of the wrong synchonization. The reason is that the second block needs the first task to be completed. Imagine that the second task carries data processing in a NSMutableArray and this array gets data from a web service that executed on the first task. So, when we try to run it we get the usual errors (EXC_BAD_ACCESS) probably because we try to access items on an empty array.
Now, the solution…
We can use two techniques:
1. Threads and Grand Central Dispatch (GCD)
According to “Waiting on Groups of Queued Tasks” in the “Dispatch Queues” chapter of Apple’s iOS Developer Library’s Concurrency Programming Guide (read here), we can use dispatch groups
Dispatch groups are a way to block a thread until one or more tasks finish executing. You can use this behavior in places where you cannot make progress until all of the specified tasks are complete. For example, after dispatching several tasks to compute some data, you might use a group to wait on those tasks and then process the results when they are done.
Let’s see the example:
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_group_t group = dispatch_group_create(); // Add a task to the group dispatch_group_async(group, queue, ^{ // Some asynchronous work }); // Do some other work while the tasks execute. // When you cannot make any more forward progress, // wait on the group to block the current thread. dispatch_group_wait(group, DISPATCH_TIME_FOREVER); // Release the group when it is no longer needed. dispatch_release(group);
or another great example:
dispatch_group_t group = dispatch_group_create();</code></pre> 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"); }); dispatch_release(group);
where dispatch_group_notify() function provides asynchronous notification of the completion of the blocks associated with the group by submitting the block to the specified queue once all blocks associated with the group have completed.
All credits for this solution goes to Mr. Jörn Eyric
2. Using NSOperationQueue
A class that regulates the execution of a set of NSOperation
objects.
Lets see the illustrating example:
<pre><code>NSOperationQueue *queue = [[NSOperationQueue alloc] init]; NSOperation *completionOperation = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"Starting 3"); }]; NSOperation *operation; operation = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"Starting 1"); sleep(7); NSLog(@"Finishing 1"); }]; [completionOperation addDependency:operation]; [queue addOperation:operation]; operation = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"Starting 2"); sleep(5); NSLog(@"Finishing 2"); }]; [completionOperation addDependency:operation]; [queue addOperation:operation]; [queue addOperation:completionOperation];
All credits of this solution goes to Mr. Rob