0

I have created an array of NSURLConnections, as I am running through a for loop and creating multiple NSURLConnections.

Here is my code

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

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

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"httpLink"]];


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

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

            m_dataPush = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO];

            [m_dataPushArray addObject:m_dataPush];

            [m_dataPush start];


}

Now as this a asynchronous task, the delegate functions will be called as below, I know how to handle one request , as below

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{

    if(connection == m_dataPush || connection == m_dataPull)
    {
        NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response;
        m_responseCode = [httpResponse statusCode];//Get status code for response

        m_ResponseData = [[NSMutableData alloc] init];
    }
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    // Append the new data to the instance variable you declared


    if(connection == m_dataPush || connection == m_dataPull)
    {
        [m_ResponseData appendData:data];
    }
}


- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    // The request is complete and data has been received
    // You can parse the stuff in your instance variable now


    if(connection == m_dataPush || connection == m_dataPull )
    {
        NSDictionary *response = [NSJSONSerialization JSONObjectWithData: m_ResponseData options: 0 error: &e];  //I am using sbjson to parse

    }   
}

But I dont know how should I handle the array of NSURLConnections in this delegate methods

esqew
  • 42,425
  • 27
  • 92
  • 132
Ranjit
  • 4,576
  • 11
  • 62
  • 121

2 Answers2

3

It's just like one, except the delegate needs to keep state for all of them. In the minimal delegate code, that means collecting just the response data. To keep track of which is which, you need something unique about them (most of the time their requests, which is unique as a proxy for the urls). Since your requests are difficult to distinguish, a safer key is the pointer (as string) to the connection...

Declare the connection dictionary:

@property(strong, nonatomic) NSMutableDictionary *dictionary;

Create a connection and save it in the dictionary:

- (NSURLConnection *)connectionForRequest:(NSURLRequest *)request {
    NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
    NSString *key = [NSString stringWithFormat:@"%p", connection];

    // create response data for the connection and save it in the dictionary
    self.dictionary[key] = [NSMutableData data];
    return  connection;
}

Look it up when you need it and return its mutable data:

- (NSMutableData *)dataForConnection:(NSURLConnection *)connection {

    NSString *key = [NSString stringWithFormat:@"%p", connection];
    return self.dictionary[key];
}

Remove it when you're done with it:

- (void)removeConnection:(NSURLConnection *)connection {

    NSString *key = [NSString stringWithFormat:@"%p", connection];
    return [self.dictionary removeObjectForKey:key];
}

Now your loop looks like this:

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

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

    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"httpLink"]];

    // setup the request as you do in your code
    NSURLConnection *connection = [self connectionForRequest:request];
    [connection start];
}

And the delegate methods look like this:

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {

    NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
    if ([httpResponse statusCode] >= 400) {
        NSLog(@"error");
    }
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    // Append the new data to the instance variable you declared

    NSMutableData *responseData = [self dataForConnection:connection];
    [responseData appendData:data];
}


- (void)connectionDidFinishLoading:(NSURLConnection *)connection {

    NSError *e;
    NSMutableData *responseData = [self dataForConnection:connection];
    NSDictionary *result = [NSJSONSerialization JSONObjectWithData:responseData options: 0 error: &e];

    [self removeConnection:connection];

    // do whatever you do with result
}

This is fine as a general purpose pattern for creating connections and being a delegate. You can generalize creation with a method like this:

danh
  • 62,181
  • 10
  • 95
  • 136
  • Hello @danh, I cannot skip the last one, bcoz, I require it for connections which dont come underthis – Ranjit Sep 04 '14 at 14:23
  • @Ranjit - Okay. It might be simpler to just do all connections this way. There's no harm in having the dictionary contain just one connection. – danh Sep 04 '14 at 14:25
  • so now I dont require an array of connections, I should only use dictionary right. So creation of a connection and calling [connection start] in above code remains same right?So before making call to [connection start], I should add it to dictionary right? – Ranjit Sep 04 '14 at 14:29
  • my request is not different , its same always – Ranjit Sep 04 '14 at 14:36
  • @Ranjit - yes, you can always use a dictionary of connections. (See edit). One benefit is that the delegate can know if there are any connections outstanding. (Also note in the edit that I forgot to remove the connection when it's done. Added that to the didFinish method. – danh Sep 04 '14 at 14:45
  • my NSURLRequest is same always, only the connection is called as many times as based on the loop, so how will be determine it based on the request. – Ranjit Sep 04 '14 at 14:48
  • did you get what I am conveying? Please let me know if I am wrong – Ranjit Sep 04 '14 at 15:06
  • Do you mean it's the exact same request, same url, query params, everything? But it gives different responses each time you call it? – danh Sep 04 '14 at 15:10
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/60631/discussion-between-ranjit-and-danh). – Ranjit Sep 04 '14 at 15:12
  • Hello @danh, request i.e NSURLRequest is this NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"httpRequest:abc.com//folders"]]; only the json data is different everytime – Ranjit Sep 04 '14 at 15:17
  • @Ranjit - please open a question about synching when app enters/leaves background and paste a link here. – danh Jan 27 '15 at 15:30
  • Hello @danh here is the link http://stackoverflow.com/questions/28216547/efficiently-sync-data-in-ios – Ranjit Jan 29 '15 at 14:00
0

There are some approaches you can use: 1) Subclass NSURLConnection by adding a property that would be an id (similar as UIView has a tag property), so in the loop you set a the tag with some int. 2) Use + (void)sendAsynchronousRequest:(NSURLRequest *)request queue:(NSOperationQueue )queue completionHandler:(void (^)(NSURLResponse, NSData*, NSError*))handler

In the case 2, inside the block you can handle each connection separately (If you need to handle each one by a different way, this approad is not valid. 3) In my opinion this is the best way --> Create a NSMutableArray and the add your connection to the array. In the callbacks you can ask

if(connection isEqual:myConnections[0]){
    // Handle it
}

if(connection isEqual:myConnections[1]){
    // Handle it and so on
}

The third approach is good when each one needs to handle by a different way

David Bemerguy
  • 1,334
  • 11
  • 15