Search code examples
iosnsurlconnectionnsurlconnectiondelegatensmutabledata

handling response with NSURLConnection


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


Solution

  • 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: