Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to batch request with AFNetworking 2?

So I'm rewriting an app for iOS 7 with AFNetworking 2.0 and I'm running into the issue of sending a batch of requests at once and tracking their progress. In the old AFNetworking there was the enqueueBatchOfHTTPRequestOperations:progressBlock:completionBlock: method on AFHTTPClient, this is clearly refactored out and I'm a bit confused on how to enqueue multiple requests.

I have created a subclass of AFHTTPSessionManager and I'm using the POST:... and GET:... methods to communicate with the server. But I can't find anything in the code and/or docs to enqueue multiple requests at once like with the old AFHTTPClient.

The only thing I can find is the undocumented batchOfRequestOperations:progressBlock:completionBlock: method on AFURLConnectionOperation, but that looks like the iOS 6 way of doing this.

Clearly I'm missing something in the new NSURLSession concept that I should use to batch requests or looking over a new AFNetworking feature. Hope someone can help me on the right track here!

tl;dr: How can I send a batch of requests with my AFHTTPSessionManager subclass?

like image 290
Mac_Cain13 Avatar asked Oct 16 '13 21:10

Mac_Cain13


2 Answers

Thanks Sendoa for the link to the GitHub issue where Mattt explains why this functionality is not working anymore. There is a clear reason why this isn't possible with the new NSURLSession structure; Tasks just aren't operations, so the old way of using dependencies or batches of operations won't work.

I've created this solution using a dispatch_group that makes it possible to batch requests using NSURLSession, here is the (pseudo-)code:

// Create a dispatch group dispatch_group_t group = dispatch_group_create();  for (int i = 0; i < 10; i++) {     // Enter the group for each request we create     dispatch_group_enter(group);      // Fire the request     [self GET:@"endpoint.json"        parameters:nil           success:^(NSURLSessionDataTask *task, id responseObject) {                   // Leave the group as soon as the request succeeded                   dispatch_group_leave(group);           }       failure:^(NSURLSessionDataTask *task, NSError *error) {                   // Leave the group as soon as the request failed                   dispatch_group_leave(group);               }]; }  // Here we wait for all the requests to finish dispatch_group_notify(group, dispatch_get_main_queue(), ^{     // Do whatever you need to do when all requests are finished }); 

I want to look write something that makes this easier to do and discuss with Matt if this is something (when implemented nicely) that could be merged into AFNetworking. In my opinion it would be great to do something like this with the library itself. But I have to check when I have some spare time for that.

like image 187
Mac_Cain13 Avatar answered Sep 16 '22 14:09

Mac_Cain13


Just updating the thread... I had the same problem and after some researches I found some good solutions, but I decided to stick with this one:

I am using the project called Bolts. So, for the same sample above posted by @Mac_Cain13, it would be:

[[BFTask taskWithResult:nil] continueWithBlock:^id(BFTask *task) {     BFTask *task = [BFTask taskWithResult:nil];     for (int i = 0; i < 10; i++) {         task = [task continueWithBlock:^id(BFTask *task) {             return [self executeEndPointAsync];         }];     }     return task; }] continueWithBlock:^id(BFTask *task) {     // Everything was executed.     return nil; }];;  - (BFTask *) executeEndPointAsync {     BFTaskCompletionSource *task = [BFTaskCompletionSource taskCompletionSource];     [self GET:@"endpoint.json" parameters:nil       success:^(NSURLSessionDataTask *task, id responseObject) {         [task setResult:responseObject];       }       failure:^(NSURLSessionDataTask *task, NSError *error) {         [task setError:error];       }];     }];     return task.task; } 

Basically, it's stacking all of the tasks, waiting and unwrapping until there is no more tasks, and after everything is completed the last completion block is executed.

Another project that does the same thing is RXPromise, but for me the code in Bolts was more clear.

like image 26
jairobjunior Avatar answered Sep 18 '22 14:09

jairobjunior