I'm calling four methods that I want to execute in synchronous order, the first two methods are synchronous, the last two methods are asynchronous (data fetching from URLs).
Pseudo-code:
- (void)syncData {
// Show activity indicator
[object sync]; // Synchronous method
[object2 sync]; // Synchronous method
BOOL object3Synced = [object3 sync]; // Async method
BOOL object4Synced = [object4 sync]; // Async method
// Wait for object3 and object4 has finished and then hide activity indicator
}
How can I achieve this?
Use a barrier:
void dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block);
Submits a barrier block for asynchronous execution and returns immediately.
When the barrier block reaches the front of a private concurrent queue, it is not executed immediately. Instead, the queue waits until its currently executing blocks finish executing. At that point, the queue executes the barrier block by itself. Any blocks submitted after the barrier block are not executed until the barrier block completes.
This example outputs 1 2 3 4 done
although being asynchronous, it could be 1 2 4 3 done
. Since I understand you want to handle an activity indicator, this shouldn't matter.
#import <Foundation/Foundation.h>
int main(int argc, char *argv[]) {
@autoreleasepool {
dispatch_queue_t queue = dispatch_queue_create("com.myqueue", 0);
dispatch_sync(queue, ^(){NSLog(@"1");} );
dispatch_sync(queue, ^(){NSLog(@"2");});
dispatch_async(queue, ^(){NSLog(@"3");});
dispatch_async(queue, ^(){NSLog(@"4");});
dispatch_barrier_sync(queue, ^(){NSLog(@"done");});
}
}
For other ways to test asynchronous code, see: https://stackoverflow.com/a/11179523/412916
Assuming you actually have some sort of way of knowing when the asynchronous methods are done, what you probably want is something like:
- (void)syncData {
// Show activity indicator
[object sync]; // Synchronous method
[object2 sync]; // Synchronous method
_object3Synced = _object4Synced = NO;
[object3 syncWithCompletionHandler:
^{
_object3Synced = YES;
[self considerHidingActivityIndicator];
}]; // Async method
[object4 syncWithCompletionHandler:
^{
_object4Synced = YES;
[self considerHidingActivityIndicator];
}]; // Async method
}
- (void)considerHidingActivityIndicator
{
if(_object3Synced && _object4Synced)
{
// hide activity indicator, etc
}
}
You can make a subclass of UIActivityInidicator
, add an activityCount
property and implement these two additional methods:
- (void)incrementActivityCount
{
if(_activityCount == 0)
{
[self startAnimating];
}
_activityCount++;
}
- (void)decrementActivityCount
{
_activityCount--;
if(_activityCount <= 0)
{
_activityCount = 0;
[self stopAnimating];
}
}
Now whenever you start something that uses the activity counter call incrementActivityCount
and in its completion block (or otherwise when it finishes) call decrementActivityCount
. You can do other things if you want in these methods, the above is just a simple example which is probably sufficient in most cases (especially if you set hidesWhenStopped = YES
).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With