Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

dispatch_group_notify does not wait for one dispatch_group_async

Two concurrent background tasks need to patch two separate arrays which need to be merged in a dispatch_group_notify block.The problem is that.the first block is exceeded but the dispatch_group_notify is exceeded without waiting for the execution of the second background task. The only different between them is that the first one make a local search and the second one makes a remote call to a web service.Any clue why the second one is jumped over ?

Edit: I also tried the approach mentioned in https://stackoverflow.com/a/19580584/859742 using dispatch_barrier_async but still same.

 dispatch_group_t taskGroup = dispatch_group_create(); 
 dispatch_queue_t mainQueue = dispatch_get_main_queue();

__block NSArray *localAddresses;
__block NSArray *remoteAddresses;

//Get local array in the background 
dispatch_group_async(taskGroup, mainQueue, ^{
    //localAddresses  is set
});

//get remote array from server
dispatch_group_async(taskGroup, mainQueue, ^{
 [[MDAddressManager instance] searchForPlacesContainingText:query
                                                      location:alocation
                                                    completion:^(NSArray* addresses, MDError *error){
       //remoteAddresses is set
});


//Merge two arrays
dispatch_group_notify(taskGroup, mainQueue, ^{
   //remoteAddresses and local addresses are merged
});

And the remote search method looks like this

- (void)searchForPlacesContainingText:(NSString *)searchText
                         location:(CLLocation *)alocation
                       completion:(MDAddressManagerBlock)completionBlock
{
NSDictionary *parameters = [[NSMutableDictionary alloc] init];

[parameters setValue:searchText forKey:@"input"];

[[MDHTTPClient sharedHTTPClient] getPath:@"v1/remotePlaces.json"
                              parameters:parameters
                                 success:^(AFHTTPRequestOperation *operation, id dict) {

    if ([MDHTTPClient isResponseValid:dict])
    {
            completionBlock(returnArray, nil);
    }
    else
    {
            completionBlock(nil, nil);
    }

} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    EDLog(@"%@", error);
    completionBlock(nil, [MDError errorAFNetworking:error]);
}];
}
like image 927
Ilker Baltaci Avatar asked May 23 '14 12:05

Ilker Baltaci


1 Answers

This is because your getPath method runs asynchronously. You need it to not leave the group until that completion block runs. So rather than than doing dispatch_group_async, you should manually dispatch_group_enter and dispatch_group_leave.

You can change your code from:

dispatch_group_async(taskGroup, mainQueue, ^{
    [[MDAddressManager instance] searchForPlacesContainingText:query
                                                      location:alocation
                                                    completion:^(NSArray* addresses, MDError *error){
        //remoteAddresses is set
    }];
});

To:

dispatch_group_enter(taskGroup);

[[MDAddressManager instance] searchForPlacesContainingText:query
                                                  location:alocation
                                                completion:^(NSArray* addresses, MDError *error){
    //remoteAddresses is set
    dispatch_group_leave(taskGroup);
});

That will ensure that you don't leave the group until the completion block is called.


Alternatively, you could change searchForPlacesContainingText to use dispatch_group_t parameter:

- (void)searchForPlacesContainingText:(NSString *)searchText
                             location:(CLLocation *)alocation
                                group:(dispatch_group_t)group
                           completion:(MDAddressManagerBlock)completionBlock
{
    dispatch_group_enter(group);

    NSDictionary *parameters = [[NSMutableDictionary alloc] init];

    [parameters setValue:searchText forKey:@"input"];

    [[MDHTTPClient sharedHTTPClient] getPath:@"v1/remotePlaces.json"
                                  parameters:parameters
                                     success:^(AFHTTPRequestOperation *operation, id dict) {

        if ([MDHTTPClient isResponseValid:dict])
        {
                completionBlock(returnArray, nil);
        }
        else
        {
                completionBlock(nil, nil);
        }

        dispatch_group_leave(group);

    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
        EDLog(@"%@", error);
        completionBlock(nil, [MDError errorAFNetworking:error]);

        dispatch_group_leave(group);
    }];

}

and change your invocation so that it doesn't do dispatch_group_async, but rather just passes the taskGroup parameter:

[[MDAddressManager instance] searchForPlacesContainingText:query
                                                  location:alocation
                                                     group:taskGroup
                                                completion:^(NSArray* addresses, MDError *error) {
    //remoteAddresses is set
});
like image 165
Rob Avatar answered Oct 15 '22 01:10

Rob