0

I am calling NSURLConnection asynchronous method calls in my view controller. I would like to handle TWO RESPONSES FOR TWO REQUEST in the same Delegate. Please suggest me what would the best approach to achieve this? I'm developing in iOS 5 SDK.

UPDATED:

 // Class A
 [serverconns setDelegate:self];
 connection = [serverconns executeAsyncHttpPost :firstjsonrequest];

 [serverconns setDelegate:self];
 connection = [serverconns executeAsyncHttpPost :secondjsonrequest];


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

- (void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    [self.appendData appendData:data];
}

- (void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
    // logs the error
}

- (void) connectionDidFinishLoading:(NSURLConnection *)connection
{
    NSData *responseData = [[NSData alloc] initWithData:appendData];
    //HOW CAN WE HANDLE TWO RESPONSES FOR TWO REQUEST in the same Delegate
    if (responseData) 
    {
          // doing something
    }
}

    //Class B: ServerConnection

- (NSURLConnection *) executeAsyncHttpPost :(id) jsonParams
{
    NSString *urlstr = [NSString stringWithFormat:@"%@", baseURL];
    urlstr = [urlstr stringByAppendingFormat:method];

    NSURL *pUrl = [NSURL URLWithString:urlstr];

    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:pUrl];
    NSData *requestData = [NSData dataWithBytes:[jsonParams UTF8String] length:[jsonParams length]];

    [request setHTTPMethod:@"POST"];
    [request setValue:@"application/json" forHTTPHeaderField:@"Accept"];
    [request setValue:@"application/json" forHTTPHeaderField:@"Content-type"];
    [request setHTTPBody: requestData];

    return [[NSURLConnection alloc] initWithRequest:request delegate:delegateResponder startImmediately:YES];

}
    -(void) setDelegate:(id)newDelegate
{
    delegateResponder = newDelegate;
}
Getsy
  • 4,887
  • 16
  • 78
  • 139

5 Answers5

3

save your connections somewhere (maybe ivar of your delegate)

- (void) connectionDidFinishLoading:(NSURLConnection *)connection
{
    NSData *responseData = [[NSData alloc] initWithData:appendData];
    //HOW CAN WE HANDLE TWO RESPONSES FOR TWO REQUEST in the same Delegate
    if (responseData) 
    {
        if (connection == yourFirstConnection) {
            // doing something for first connection
        } else {
            // doing something for second connection
        }
    }
}

just point out some minor problem of your code

NSString *urlstr = [NSString stringWithFormat:@"%@", baseURL];
urlstr = [urlstr stringByAppendingFormat:method];

should replace to

NSString *urlstr = [baseURL absoluteString];
urlstr = [urlstr stringByAppendingString:method];

and add two(or more or array) weak/assign property of NSURLConnection to your class A (connection delegate)

@property (assign) NSURLConnection *myFirstConnection;
@property (assign) NSURLConnection *mySecondConnection;
// assume only need to handle two connection otherwise NSArray should be used instead

than in your class B (create connection)

- (NSURLConnection *) executeAsyncHttpPost :(id) jsonParams
{
    NSString *urlstr = [baseURL absoluteString];
    urlstr = [urlstr stringByAppendingString:method];

    NSURL *pUrl = [NSURL URLWithString:urlstr];

    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:pUrl];
    NSData *requestData = [NSData dataWithBytes:[jsonParams UTF8String] length:[jsonParams length]];

    [request setHTTPMethod:@"POST"];
    [request setValue:@"application/json" forHTTPHeaderField:@"Accept"];
    [request setValue:@"application/json" forHTTPHeaderField:@"Content-type"];
    [request setHTTPBody: requestData];

    NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:delegateResponder startImmediately:YES];
    delegateResponder.myFirstConnection = connection;
    // delegateResponder.mSecondConnection = connection;
    return connection;

}
Bryan Chen
  • 45,816
  • 18
  • 112
  • 143
  • OK..But, please see i updated the code above. There are two classes i'm using. Do you still think, i can create two different NSURLConnection obj and use it later? – Getsy Feb 11 '12 at 07:56
  • It says, property myFirstConnection not found, even though declared it. And also, how can we add condition for the second one? – Getsy Feb 11 '12 at 13:17
2

If I were you I would create a CustomClass which inherits the NSURLConnection. And I will add property called tag.

When I initiate the CustomClass, I would set the tag property and use that to determine which request is being worked on

CustomURLConnection *connection = [[CustomURLConnection alloc] initWithRequest:request delegate:self tag:1];

- (id)initWithRequest:(NSURLRequest *)request delegate:(id)delegate   tag:(int)_tag
 {
if(self = [super initWithRequest:request delegate:delegate])
{   
   self.tag = _tag;
}

Now in the code you posted add this

- (void) connectionDidFinishLoading:(NSURLConnection *)connection
{
    NSData *responseData = [[NSData alloc] initWithData:appendData];
    //HOW CAN WE HANDLE TWO RESPONSES FOR TWO REQUEST in the same Delegate
    if (responseData) 
    {
      if (connection.tag == 1){

      }
    }
}

return self;
  }
mbh
  • 3,302
  • 2
  • 22
  • 24
  • i don't think it is a good idea to compare using == `if (connection.tag == @"Conn A")` – Bryan Chen Feb 11 '12 at 04:50
  • Thanks for pointing that out. Changed to int. Was basically trying to recreate the idea from ASIHTTPRequest – mbh Feb 11 '12 at 04:51
  • OK..But, please see i updated the code above. There are two classes i'm using. Delegate methods are in different file. Do you still think, i can go ahead with your suggestion? – Getsy Feb 11 '12 at 07:57
  • I am not able to find this condition properly-> if (connection.tag == 1) from my Class A. Because i have delegate methods in this class, but the request call is done in Class B. Any helps please? – Getsy Feb 11 '12 at 08:53
  • Ok..lets say, i set this tag value in Class A just before executeAsyncHttpPost calls. But, executeAsyncHttpPost is called twice there, one after another..So, how can connectionDidFinishLoading find this tag value properly for two server responses in the same class file? I don't think it is possible to find condition (connection.tag == 1) if i use urlconnection delegate methods in another class, like my class A. – Getsy Feb 11 '12 at 09:13
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/7556/discussion-between-getsy-and-mbh) – Getsy Feb 11 '12 at 09:25
1

I think all the mentioned solutions are "ugly". I would not implement a solution with delegate methods but instead create a blocks-based solution. I could post an example if you're interested. I would make use of the AFNetworking classes for this approach.


What follows is an example of a class that handles 2 different responses without using a delegate implementation, opting for blocks instead with the AFNetworking library.

- (void)JSONFromService
{
    // create the first request and set the methods that handle the return values (either NSData or NSError in this case) in blocks ... 

    NSURL *firstURL = [NSURL URLWithString:@"http://dl.dropbox.com/u/6487838/test1.html"];
    NSURLRequest *firstRequest = [NSURLRequest requestWithURL:firstURL];
    AFHTTPRequestOperation *firstOperation = [[AFHTTPRequestOperation alloc] initWithRequest:firstRequest];

    [firstOperation setCompletionBlockWithSuccess:^ (AFHTTPRequestOperation *operation, id object) 
    {
        NSString *firstString = [[NSString alloc] initWithData:object encoding:NSASCIIStringEncoding];
        NSLog(@"%@", firstString);
    } failure:^ (AFHTTPRequestOperation *operation, NSError *error) {
        NSLog(@"%@", error);
    }];
    [firstOperation start];



    // create the second request and set the methods that handle the return values (either NSData or NSError in this case) in blocks ... 

    NSURL *secondURL = [NSURL URLWithString:@"http://dl.dropbox.com/u/6487838/test2.html"];
    NSURLRequest *secondRequest = [NSURLRequest requestWithURL:secondURL];
    AFHTTPRequestOperation *secondOperation = [[AFHTTPRequestOperation alloc] initWithRequest:secondRequest];

    [secondOperation setCompletionBlockWithSuccess:^ (AFHTTPRequestOperation *operation, id object) {
        NSString *secondString = [[NSString alloc] initWithData:object encoding:NSASCIIStringEncoding];
        NSLog(@"%@", secondString);
    } failure:^ (AFHTTPRequestOperation *operation, NSError *error) {
        NSLog(@"%@", error);
    }];
    [secondOperation start];
}
Wolfgang Schreurs
  • 11,779
  • 7
  • 51
  • 92
0

I usually subclass NSURLConnection and add properties to store whatever context I need to handle the response.

Since the delegate methods get NSURLConnection passed in, you can just cast it back to your subclass and access the context.

Take a look at this example.

Community
  • 1
  • 1
pepsi
  • 6,785
  • 6
  • 42
  • 74
  • I am not getting properly from this example. Please look into my updated code, i have delegate methods from the caller, not in the request class. – Getsy Feb 11 '12 at 10:45
0

I think you should keep all of your connections in an activeConnections array. Every time one finishes, you do [activeConnections indexForObject:connection] and you update your delegate method accordingly, using the index.

Now, a cleaner way to do it( and a better way from my point of view, but this depends on how large is the data you want to transfer) is to use queues. I'll provide a small example and add comments to it:

// we assume you have 2 requests: req1, req2

//now, create a new dispatch queue    
dispatch_queue_t netQueue = dispatch_queue_create("com.mycompany.netqueue",DISPATCH_QUEUE_SERIAL);

//execute the operations in the queue ASYNC
//is very important to dispatch this ASYNC on a background thread, otherwise your UI will be stuck until the request finishes 
dispatch_async(netQueue, 
^{
  // We are on a background thread, so we won't block UI events (or, generally, the main run loop)
  NSHTTPURLResponse *response = nil;
  NSError *error = nil;
  NSData *data = nil;




  //We can call the request synchronous and block this thread until completed
  data = [NSURLConnection sendSynchronousRequest:req1
                               returningResponse:&response 
                                           error:&error];

  dispatch_async(dispatch_get_main_queue(),
  ^{
    //call your delegate with the appropriate method for req1 
    //be sure to copy the contents in data, as we will reuse it with the next request 
  });

  //We can call the other request synchronous and block this thread until completed
  data = [NSURLConnection sendSynchronousRequest:req2
                               returningResponse:&response 
                                           error:&error];
  dispatch_async(dispatch_get_main_queue(),
  ^{
  //call your delegate with the appropriate method for req2 
  });




  //and this can go on forever. If you have many requests to execute, simply put them in a loop


 });
 dispatch_release(netQueue);
Rad'Val
  • 8,895
  • 9
  • 62
  • 92