Start NSURLConnection requests serially

2019-09-02 12:31发布

I'm looping through an array which contains few strings and making a request to a web server for each strings in the array.

I would like each request to be processed completely before the subsequent request is sent to the server. Because each request sends me a response which I will send with next request and so on.

The problem I am having is that my NSURLConnection is set up using the standard asynchronous call. This results in requests not blocking any subsequent requests. But I need to block other requests in the loop before first completes.

The request URL is same always , only JSON data changes with every request in the loop. Here is my code

for (int i = 0; i < array.count; i++)
{


     NSData *jsonData = [NSJSONSerialization dataWithJSONObject:finalJSON options:NSJSONWritingPrettyPrinted error:&error];
     if (!jsonData) {
                NSLog(@"Error creating JSON object: %@", [error localizedDescription]);
            }


      NSString *url = [NSString stringWithFormat:@“abc.com/folders”];

      NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]];

      [request setValue:@"application/json;charset=utf-8" forHTTPHeaderField:@"Content-Type"];
      [request setValue:APIKEY forHTTPHeaderField:@"X_API_KEY"];

      [request setHTTPMethod:@"POST"];
      [request setHTTPBody:jsonData];

            //I am adding all connections to NSDictionary so that later I can process request.
      NSURLConnection *connection = [self connectionForRequest:request];
      [connection start];                

}

2条回答
虎瘦雄心在
2楼-- · 2019-09-02 12:46

I thought of 2 solutions for your problem:

  1. AFNetworking - U can use AFNetworking and maintain a counter in the success block. The counter will count the requests and when all done, will do your next task.

  2. GCD - Dispatch Groups - Grand Central Dispatch provide u the option to make group or requests and do something at the end (when all the requests finished). For that, u need to read nice tutorial (2nd part of "Ray Wenderlich". If U r not familiar with GCD, jump to the tutorial 1st part).

Anyway, With your code above U can't achieve your task. U don't have any async block which run at the end of the requests.

Edit:

Use AFNetworking:

U must remove your for loop first, and then do like this:

AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
NSDictionary *parameters = @{@"foo": @"bar"};
[manager POST:@"http://example.com/resources.json" parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject) { // HERE u can do your second request which uses the first response

        AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
        NSDictionary *parameters_new = <USE_YOUR_DATA_FROM_responseObject>;
        [manager POST:@"http://example.com/resources.json" parameters:parameters      success:^(AFHTTPRequestOperation *operation, id responseObject) { // HERE u can do your third request which uses the first and second response



        } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
             NSLog(@"Error: %@", error);
        }]; 


} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    NSLog(@"Error: %@", error);
}];
查看更多
女痞
3楼-- · 2019-09-02 12:54

A simple way to do this is with recursion. Create a method that sends the url connection, and, once the connection is complete, calls itself to send it again.

Here's the key to the solution: make a method that can be called recursively, which sends requests and collects results. By calling itself recursively in the completion block, this method sees to it that each request starts after the previous one finishes...

// note - edited per the comments to get a new NSURLRequest each time
- (void)makeRequests:(NSInteger)count
             results:(NSMutableArray *)results
          completion:(void (^)(NSError *))completion {

    // complete recursion
    if (count == 0) return completion(nil);

    NSURLRequest *request = [self nextRequest];

    [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {

        if (!error) {
            [results addObject:data];
            [self makeRequests:count-1 results:results completion:completion];
        } else {
            completion(error);
        }
    }];
}

To call it, allocate an array that will carry the results...

- (void)makeManyRequests {

    NSMutableArray *resultsArray = [NSMutableArray array];
    [self makeRequests:10 results:resultsArray completion:^(NSError *error) {
        NSLog(@"done.  results are %@", resultsArray);
    }];
}

EDIT - Its unclear in the OP how this request changes each time, but it sounds like you have that figured out. This is just your originally posted code in its own method. Its a good idea to factor this out so your code can be clear on how it forms a different JSON payload each time...

- (NSURLRequest *)nextRequest {

    id finalJSON = // your app supplies...
    // somehow, this changes each time nextRequest is called

    NSString *APIKEY = // your app supplies
    NSError *error;

    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:finalJSON options:NSJSONWritingPrettyPrinted error:&error];
    if (!jsonData) {
        NSLog(@"Error creating JSON object: %@", [error localizedDescription]);
    }

    // your request creation code, copied from the OP
    NSString *url = [NSString stringWithFormat:@"abc.com/folders"];

    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]];

    [request setValue:@"application/json;charset=utf-8" forHTTPHeaderField:@"Content-Type"];
    [request setValue:APIKEY forHTTPHeaderField:@"X_API_KEY"];
    [request setHTTPMethod:@"POST"];
    [request setHTTPBody:jsonData];
    return request;
}
查看更多
登录 后发表回答