Here is my concern: For some reason, I have to retrieve and group the answer coming from 3 different web request results. Once the 3 of them have return, I must then call a completionBlock and pass it all the results. Using NSOperation API, I managed to do something like that :
Session * session = [[ServiceLocator sharedInstance] serviceForName:ServiceLocatorNameUserRepository];
NSString * urlMethod = @"POST";
NSDictionary * params = @{kParkadomWebServiceUser : session.currentUser.userID};
NSMutableDictionary * records = [NSMutableDictionary new];
NSOperation * currentBooking = [self performRequestWithPath:API_BOOKING_INPROGRESS
method:urlMethod
parameter:params
completion:^(id json, NSError * error)
{
records[@"current"] = error ? error : json;
}];
NSOperation * upcomingBookings = [self performRequestWithPath:API_BOOKING_UPCOMING
method:urlMethod
parameter:params
completion:^(id json, NSError * error)
{
records[@"upcoming"] = error ? error : json;
}];
NSOperation * pastBookings = [self performRequestWithPath:API_BOOKING_HISTORY
method:urlMethod
parameter:params
completion:^(id json, NSError * error)
{
records[@"past"] = error ? error : json;
}];
NSBlockOperation * completionOperation = [NSBlockOperation blockOperationWithBlock:^{
completion([records copy], nil);
}];
[completionOperation addDependency:currentBooking];
[completionOperation addDependency:upcomingBookings];
[completionOperation addDependency:pastBookings];
[[NSOperationQueue mainQueue] addOperation:completionOperation];
where completion is obviously the completion block given as an entry parameter. The performRequestWithPath:method:parameter:completion: create an NSOperation, adds it to a global queue and returns it, so I have my 3 web calls here. Then I create a block operation and adds the dependency to the 3 previous block so it is not fired before the 3 blocks did complete.
My concern is over the NSMutableArray thingy. It's seems like a poor design to do something like this and I'm not sure if it's really bug proof in case 2 calls finished exactly at the same time. (note that I made sure in the perform...: method that the completion block is called in the main queue).
Any feedback? Suggestions, criticism, theory... I'm all open :)
You will need to add synchronization.
@synchronized(myArray) {
[myArray doSomething];
}
For example, in your code:
@synchronized(records) {
records[@"past"] = error ? error : json;
}
Edit: @gnasher729 brings up the good point that if they completion blocks are run on the main thread, then there is no need for synchronization.