The problem with asynchronous requests is when you have various requests going off, and you have a delegate assigned to treat them all as one entity, a lot of branching and ugly code begins to formulate going:

What kind of data are we getting back? If it contains this, do that, else do other. It would be useful I think to be able to tag these asynchronous requests, kind of like you're able to tag views with IDs.

I was curious what strategy is most efficient for managing a class that handles multiple asynchronous requests.

It may seem odd to use this instead of NSMutableDictionary but I do it because this CFDictionary only retains its keys (the NSURLConnection) whereas NSDictionary copies its keys (and NSURLConnection doesn't support copying).

and now I have an "info" dictionary of data for each connection that I can use to track information about the connection and the "info" dictionary already contains a mutable data object that I can use to store the reply data as it comes in.

Since it is possible that two or more asynchronous connections may enter the delegate methods at a time, is there anything specific that one would need to do to ensure correct behavior?
–
PlagueHammerJul 28 '09 at 6:48

This is not thread safe if the delegate is being called from multiple threads. You must use mutual exclusion locks to protect the data structures. A better solution is subclassing NSURLConnection and adding response and data references as instance variables. I am providing a more detailed answer explaining this at Nocturne's question: stackoverflow.com/questions/1192294/…
–
James WaldDec 21 '09 at 5:11

4

Aldi... it is thread safe provided you start all connections from the same thread (which you can do easily by invoking your start connection method using performSelector:onThread:withObject:waitUntilDone:). Putting all connections in an NSOperationQueue has different problems if you try to start more connections than the max concurrent operations of the queue (operations get queued instead of running concurrently). NSOperationQueue works well for CPU bound operations but for network bound operations, you're better off using an approach that doesn't use a fixed size thread pool.
–
Matt GallagherMay 29 '10 at 4:43

1

Just wanted to share that for iOS 6.0 and above, you can use a [NSMapTable weakToStrongObjectsMapTable] instead of a CFMutableDictionaryRef and save the hassle. Worked well for me.
–
Shay AvivSep 10 '14 at 4:56

I have a project where I have two distinct NSURLConnections, and wanted to use the same delegate. What I did was create two properties in my class, one for each connection. Then in the delegate method, I check to see if which connection it is

To distinguish different NSURLConnection within same class's delegate methods, I use NSMutableDictionary, to set and remove the NSURLConnection, using its (NSString *)description as key.
The object I chose for setObject:forKey is the unique URL that is used for initiating NSURLRequest, the NSURLConnection uses.
Once set NSURLConnection is evaluated at -(void)connectionDidFinishLoading:(NSURLConnection *)connection, it can be removed from the dictionary.

// This variable must be able to be referenced from - (void)connectionDidFinishLoading:(NSURLConnection *)connection
NSMutableDictionary *connDictGET = [[NSMutableDictionary alloc] init];
//...//
// You can use any object that can be referenced from - (void)connectionDidFinishLoading:(NSURLConnection *)connection
[connDictGET setObject:anyObjectThatCanBeReferencedFrom forKey:[aConnectionInstanceJustInitiated description]];
//...//
// At the delegate method, evaluate if the passed connection is the specific one which needs to be handled differently
if ([[connDictGET objectForKey:[connection description]] isEqual:anyObjectThatCanBeReferencedFrom]) {
// Do specific work for connection //
}
//...//
// When the connection is no longer needed, use (NSString *)description as key to remove object
[connDictGET removeObjectForKey:[connection description]];

One approach I've taken is to not use the same object as the delegate for each connection. Instead, I create a new instance of my parsing class for each connection that is fired off and set the delegate to that instance.

I usually create an array of dictionaries. Each dictionary has a bit of identifying information, an NSMutableData object to store the response, and the connection itself. When a connection delegate method fires, I look up the connection's dictionary and handle it accordingly.

Ben, would it be okay to ask you for a piece of sample code? I'm trying to envision how you're doing it, but it's not all there.
–
Coocoo4CocoaDec 1 '08 at 21:41

In particular Ben, how do you look up the dictionary? You can't have a dictionary of dictionaries since NSURLConnection doesn't implement NSCopying (so it can't be used as a key).
–
Adam ErnstDec 1 '08 at 22:19

Matt has an excellent solution below using CFMutableDictionary, but I use an array of dictionaries. A lookup requires an iteration. Its not the most efficient, but it's fast enough.
–
Ben GottliebDec 2 '08 at 0:10

One option is just to subclass NSURLConnection yourself and add a -tag or similar method. The design of NSURLConnection is intentionally very bare bones so this is perfectly acceptable.

Or perhaps you could create a MyURLConnectionController class that is responsible for creating and collecting a connection's data. It would then only have to inform your main controller object once loading is finished.

I really like the 'blocks' implementation in ASIHTTPRequest - it's just like Anonymous Inner Types in Java. This beats all the other solutions in terms of code cleanliness and organisation.
–
Matt LyonsJun 19 '11 at 8:54

I decided to subclass NSURLConnection and add a tag, delegate, and a NSMutabaleData. I have a DataController class that handles all of the data management, including the requests. I created a DataControllerDelegate protocol, so that individual views/objects can listen to the DataController to find out when their requests were finished, and if needed how much has been downloaded or errors. The DataController class can use the NSURLConnection subclass to start a new request, and save the delegate that wants to listen to the DataController to know when the request has finished. This is my working solution in XCode 4.5.2 and ios 6.

The DataController.h file that declares the DataControllerDelegate protocol). The DataController is also a singleton: