andre
andre

Reputation: 7249

Objective-c: How to make multiple async service calls and block until they are all complete

I have a senario that requires me to make multiple call to a web api. The following is an example.

getDataAsync:(NSDictionary *)dictionary withCompletion: (void (^)(NSDictionary*))completion {

    __block int counter = n; // the number of async blocks
    __block NSMutableDictionary *output = [[NSMutableDictionary alloc] init];
    void (^returnBlock)(void) = ^{
        counter--;
        if(counter != 0) return;
        completion(@{@"return": output});
        return;
    };
    void (^getResourceA)(void) = ^{
        [service getResourceA : dictionary[@"idA"] completion:
        ^(ServiceResult results, MyResourceA *a, NSString *errMsg) {
            [output setValue:a.value forKey:a.name];
            returnBlock(); 
        }];
    };
    // followed by n-1 other blocks like getResourceA
    //... 
}

I want to use the built in dispatch_queue rather than my own custom solution here. How can I do that given the inner completion block used by the asynchronous service call?

Also any other advice on how to go about this would be appreciated.

Upvotes: 1

Views: 1524

Answers (2)

Jesper
Jesper

Reputation: 7605

Use dispatch_group_t. See Waiting on Groups of Queued Tasks.

The topic doesn't mention it, but use dispatch_group_notify to register a block instead of waiting inline.

Upvotes: 1

Leo
Leo

Reputation: 38180

Dispatch groups have been invented for this purpose:

dispatch_group_t requestGroup = dispatch_group_create();
dispatch_group_async(requestGroup, queue, ^{
    // ...
});
dispatch_group_wait(requestGroup, DISPATCH_TIME_FOREVER);
completionBlock();

Or instead of waiting:

dispatch_group_notify(requestGroup, dispatch_get_main_queue(), ^{
    completionBlock();
});

Also, instead of dispatching blocks to the group, you can also enter and leave a group manually, which works well with asynchronous service APIs:

dispatch_group_enter(requestGroup);
[service getResourceA : dictionary[@"idA"] completion: ^(ServiceResult results, MyResourceA *a, NSString *errMsg) {
    [output setValue:a.value forKey:a.name];
    dispatch_group_leave(requestGroup);
}];

Upvotes: 7

Related Questions