After posting the custom NSURLConnection subclass blog post, I thought I might post an example of how it would be used, since quite a lot of visitors came to the blog searching for the keywords: “multiple asynchronous NSURLConnection”. The code itself is pretty straightforward, but might prove handy for those developers setting their first steps in Cocoa Touch.
The basic idea is to use a dictionary which stores the received data per tag, remember that the actual connection cannot be used as the key of a dictionary. Each NSURLConnection methods retrieve the NSMutableData object from the dictionary based on the tag and does it magic with it.
If you don’t know how to use the NSURLConnection class, take a look at the documentation. That should get you going in no time.
First of all add a mutable dictionary to the header file:
NSMutableDictionary *receivedData;
Here’s the actual code. The load method starts the actual asynchronous calls. The startAsyncLoad:tag and dataForConnection methods are convenience methods to keep the code tidy & readable.
- (void)startAsyncLoad:(NSURL*)url tag:(NSString*)tag { NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; CustomURLConnection *connection = [[CustomURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES tag:tag]; if (connection) { [receivedData setObject:[[NSMutableData data] retain] forKey:connection.tag]; } } - (NSMutableData*)dataForConnection:(CustomURLConnection*)connection { NSMutableData *data = [receivedData objectForKey:connection.tag]; return data; } - (void)load { receivedData = [[NSMutableDictionary alloc] init]; NSURL *url1 = [NSURL URLWithString:@"http://blog.emmerinc.be"]; NSURL *url2 = [NSURL URLWithString:@"http://www.emmerinc.be"]; NSURL *url3 = [NSURL URLWithString:@"http://twitter.com/emmerinc"]; [self startAsyncLoad:url1 tag:@"tag1"]; [self startAsyncLoad:url2 tag:@"tag2"]; [self startAsyncLoad:url3 tag:@"tag3"]; } - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { NSMutableData *dataForConnection = [self dataForConnection:(CustomURLConnection*)connection]; [dataForConnection setLength:0]; } - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { NSMutableData *dataForConnection = [self dataForConnection:(CustomURLConnection*)connection]; [dataForConnection appendData:data]; } - (void)connectionDidFinishLoading:(NSURLConnection *)connection { NSMutableData *dataForConnection = [self dataForConnection:(CustomURLConnection*)connection]; [connection release]; // Do something with the dataForConnection. }
In the connectionDidFinishLoading: method the tag of the connection should be used to determine what to do with the actual received data. And that is about it!
Don’t forget to release the dictionary in the deconstructor or after all the asynchronous calls have been completed though.
Tags: asynchronous, NSURLConnection
Awesome! Bookmarking this now as I’m sure to use it. Thanks for the write-up.
Awesome tut! Thank you, this was exactly what I was looking for.
One question though, in the connectionDidFinishLoading: method, are you getting the tag and deciphering what to do from the dataForConnection or the connection passed in? and if it’s from the dataForConnection that you’re setting, how do you go about getting it?
Thanks again!
I would use the tag of the connection (passed in the method) to determine what to do with the data in dataForConnection. Think I would put an if-else block to check the tag and perform some kind of logic on the data.
I’m sure there’ll be better (and cleaner) ways though to achieve this though. Thanks for the comments by the way.
Thank very much! It’s wonderful!
Very simple and clean method!
beautiful work,
one of the things i had to do to make the tag accessible in connectionDidFinishLoading is change from NSURLConnection to CustomURLConnection in order to have the tag passed:
- (void)connectionDidFinishLoading:(CustomURLConnection *)connection {
NSMutableData *dataForConnection = [self dataForConnection:(CustomURLConnection*)connection];
[connection release];
//now access tag as string
if([connection.tag isEqualToString:@"tag1"]{
//do something with data
}
}
was this the intention or did i miss something?!
@chez: I would personally leave NSURLConnection in the method signature and cast it to CustomURLConnection in the method itself. After you casted it, you could use that object in your if-condition. Although in essence your doing the same thing.
Thanks a bunch for this tutorial. That’s exactly what I was searching for. I did the same in my app and it works like a charm! I’ll definitely mention this page on my own iphone blog.
Hi,
Is there a limit on the number of async NSURLConnections that can be started on the device?
Thanks,
Teja.
To my knowledge there is no limit, although you want to keep the amount of simultaneous connections to a minimum.
Thank you, but, Man, comment your code please, it takes 1 minute …
When i run your code it tells me : CustomURLConnectionundeclard, first use in this function.
You have an idea why ?
Have you copied the CustomURLConnection class in your project? It can be found in the blog post linked to at the top of this post. Don’t forget to #import the CustomURLConnection class when you want to use it.
Thanks for the answer. But it will be very hard to customize it, cuz customizing an uncommented code is much harder than creating a new one, so i’m gonna creat mine
Thank you
. . . but you code works well, i recommend it .
7 methods is not a lot of code James, really
hmmm yes you’re right. took 5 minutes to understand it and it’s ok, it’s easy
For people who don’t know what to do with the last NSMutableData, just convert it to tring like this :
// convert the dataForConnection
NSString *string=[[NSString alloc] initWithData:dataForConnection encoding:NSASCIIStringEncoding];
//Display it in console to test if it works.
NSLog(@”The result : %@”,string);
Thank you so much for the class, it will be much helpful
Nice tutorial,
can you post a sample on how the cancel and fail would work?