0
votes

My scene is like this, first I have a server json api which return some data for specify page, the api is like /data/page/1. For this case, suppose the response data is :

page 1 => ['a','b']
page 2 => ['c','d']
page 3 => ['e','f']

I use AFNetworking 2 to fetch data from api, for single page data request it works well.

The problem is now I want to implement parallel request for more than one page. I need one api for view controller which accept one pages number, and callback with all data for these pages collected. The api I need is:

typedef void (^DataBlock)(id data);

- (void) dataForPages:(NSInteger)pages withSuccessBlock:(DataBlock)block;

If view controller pass 3 for pages parameter, I want AFNetworking can request data parallel and then collected the 3 result then use in callback block.

I tried to use NSOperationQueue to process multi AFHTTPRequestOperation but failed, the code demo is like this:

- (void) dataForPages:(NSInteger)pages withSuccessBlock:(DataBlock)block
{

    //want to use for each, here suppose pages is 3

    NSMutableArray *result = [[NSMutableArray alloc] init];

    AFHTTPRequestOperation  *op1 = [[AFHTTPRequestOperation alloc] initWithRequest:@"/data/page/1"];
    AFHTTPRequestOperation  *op2 = [[AFHTTPRequestOperation alloc] initWithRequest:@"/data/page/2"];
    AFHTTPRequestOperation  *op3 = [[AFHTTPRequestOperation alloc] initWithRequest:@"/data/page/3"];


    [op1 setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
        [result addObjectsFromArray: responseObject];    //responseObject is ['a', 'b']
    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    }];

    [op2 setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
        [result addObjectsFromArray: responseObject];    //responseObject is ['c', 'd']
    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    }];

    [op3 setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
        [result addObjectsFromArray: responseObject];    //responseObject is ['e', 'f']
    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    }];


    NSOperationQueue *q = [[NSOperationQueue alloc] init];

    [q addOperation:op1];
    [q addOperation:op2];
    [q addOperation:op3];


    [q waitUntilAllOperationsAreFinished];


    block(result);
}

In my test the result always empty, I'm not quite understand waitUntilAllOperationsAreFinished.

Anyone knows how to deal this problem with NSOperation or GCD?

1

1 Answers

0
votes

After some code research, I found it's difficult to get what I want with NSOperation and NSOperationQueue, because AFNetworking has it's own completion block handler.

The final solution is use dispatch_group, all code is like this:

dispatch_group_t group = dispatch_group_create();


NSURLRequest *req1 = ...;
NSURLRequest *req2 = ...;

AFHTTPRequestOperation  *op1 = [[AFHTTPRequestOperation alloc] initWithRequest:req1];
AFHTTPRequestOperation *op2 = [[AFHTTPRequestOperation alloc] initWithRequest:req2];

NSMutableArray *result = [[NSMutableArray alloc] init];

dispatch_group_enter(group);     //enter group

[op1 setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
    [result addObjectsFromArray: responseObject];
    dispatch_group_leave(group);      //leave group in completion handler
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    dispatch_group_leave(group);
}];

dispatch_group_enter(group);
[op2 setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
    [result addObjectsFromArray: responseObject];
    dispatch_group_leave(group);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    dispatch_group_leave(group);
}];

[op1 start];
[op2 start];

dispatch_group_notify(group, dispatch_get_main_queue(), ^{
    block(result);
});