Wait until multiple networking requests have all executed - including their completion blocks

asynchronous, cocoa-touch, httprequest, ios, objective-c

Solution

Use dispatch groups.

dispatch_group_t group = dispatch_group_create();

MyCoreDataObject *coreDataObject;

dispatch_group_enter(group);
AFHTTPRequestOperation *operation1 = [[AFHTTPRequestOperation alloc] initWithRequest:request1];
[operation1 setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
    coreDataObject.attribute1 = responseObject;
    sleep(5);
    dispatch_group_leave(group);
}];
[operation1 start];

dispatch_group_enter(group);
AFHTTPRequestOperation *operation2 = [[AFHTTPRequestOperation alloc] initWithRequest:request1];
[operation2 setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
    coreDataObject.attribute2 = responseObject;
    sleep(10);
    dispatch_group_leave(group);
}];
[operation2 start];

dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
dispatch_release(group);

[context save:nil];

Problem

I have multiple operations (they're AFNetworking requests) with completion blocks that takes some time to execute, and a Core Data object that needs to be saved at the end of all the requests. ``` MyCoreDataObject *coreDataObject; AFHTTPRequestOperation *operation1 = [[AFHTTPRequestOperation alloc] initWithRequest:request1]; [operation1 setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { coreDataObject.attribute1 = responseObject; sleep(5); }]; [operation1 start]; AFHTTPRequestOperation *operation2 = [[AFHTTPRequestOperation alloc] initWithRequest:request1]; [operation2 setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { coreDataObject.attribute2 = responseObject; sleep(10); }]; [operation1 operation2]; [context save:nil]; ``` Of course, this does not work as I want because the requests are asynchronous. I tried adding an NSOperationQueue like so: ``` NSOperationQueue *operationQueue = [[NSOperationQueue alloc] init]; [operationQueue setMaxConcurrentOperationCount:2]; AFHTTPRequestOperation *operation1 = [[AFHTTPRequestOperation alloc] initWithRequest:request1]; [operation1 setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { coreDataObject.attribute1 = responseObject; sleep(5); }]; [operationQueue addOperation:operation1]; AFHTTPRequestOperation *operation2 = [[AFHTTPRequestOperation alloc] initWithRequest:request1]; [operation2 setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { coreDataObject.attribute2 = responseObject; sleep(10); }]; [operationQueue addOperation:operation2]; [imageQueue waitUntilAllOperationsAreFinished]; [context save:nil]; ``` This looks a bit better. Using `waitUntilAllOperationsAreFinished`, my queue blocks the current thread until my requests are finished, but not until my success Blocks are finished, which is really what I need. Any ideas on how to achieve this in a good way?

Original source