I don't know of any automatic mechanism to do this. So you have to write a new class yourself (let's call it ConnectionQueue
):
Basically, instead of a creating the NSURLConnection
directly, you call a method of your ConnectionQueue
class (which should have exactly one instance) taking the NSURLRequest
and the delegate as a parameter. Both are added to a queue, i.e. a separate NSArray
for the requests and the delegates.
If the arrays contains just one element, then no request is outstanding and you can create a NSURLConnection
with the specified request. However, instead of the delegate passed to the method, you pass your ConnectionQueue
instance as the delegate. As a result, the connection queue will be informed about all actions of the connection. In most cases, you just forward the callback to the original delegate (you'll find it in the first element of the delegate array).
However, if the outstanding connection completes (connection:didFailWithError:
or connectionDidFinishLoading:
is called), you first call the original delegate and then remove the connection from the two arrays. Finally, if the arrays aren't empty, you start the next connection.
Update:
Here's some code. It compiles but hasn't been tested otherwise. Furthermore, the implementation of the NSURLConnectionDelegate
protocol is incomplete. If you're expecting more than implemented callbacks, you'll have to add them.
Header File:
#import <Foundation/Foundation.h>
@interface ConnectionQueue : NSObject {
NSMutableArray *requestQueue;
NSMutableArray *delegateQueue;
NSURLConnection *currentConnection;
}
// Singleton instance
+ (ConnectionQueue *)sharedInstance;
// Cleanup and release queue
+ (void)releaseShared;
// Queue a new connection
- (void)queueRequest:(NSURLRequest *)request delegate:(id)delegate;
@end
Implementation:
#import "ConnectionQueue.h"
@implementation ConnectionQueue
static ConnectionQueue *sharedInstance = nil;
+ (ConnectionQueue*)sharedInstance
{
if (sharedInstance == nil)
sharedInstance = [[ConnectionQueue alloc] init];
return sharedInstance;
}
+ (void)releaseShared
{
[sharedInstance release];
sharedInstance = nil;
}
- (id)init
{
if ((self = [super init])) {
requestQueue = [NSMutableArray arrayWithCapacity:8];
delegateQueue = [NSMutableArray arrayWithCapacity:8];
}
return self;
}
- (void)dealloc
{
[requestQueue release];
[delegateQueue release];
[currentConnection cancel];
[currentConnection release];
[super dealloc];
}
- (void)startNextConnection
{
NSURLRequest *request = [requestQueue objectAtIndex:0];
currentConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
}
- (void)queueRequest:(NSURLRequest *)request delegate:(id)delegate
{
[requestQueue addObject:request];
[delegateQueue addObject:delegate];
if ([requestQueue count] == 1)
[self startNextConnection];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
id delegate = [delegateQueue objectAtIndex:0];
[delegate connection: connection didReceiveResponse: response];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
id delegate = [delegateQueue objectAtIndex:0];
[delegate connection: connection didReceiveData: data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
id delegate = [delegateQueue objectAtIndex:0];
[delegate connection: connection didFailWithError:error];
[currentConnection release];
currentConnection = nil;
[requestQueue removeObjectAtIndex:0];
[delegateQueue removeObjectAtIndex:0];
if ([requestQueue count] >= 1)
[self startNextConnection];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
id delegate = [delegateQueue objectAtIndex:0];
[delegate connectionDidFinishLoading: connection];
[currentConnection release];
currentConnection = nil;
[requestQueue removeObjectAtIndex:0];
[delegateQueue removeObjectAtIndex:0];
if ([requestQueue count] >= 1)
[self startNextConnection];
}
@end
To use the connection queue, create an NSURLRequest instance and then call:
[[ConnectionQueue sharedInstance] queueRequest:request delegate:self];
There's no need to create the singleton instance of ConnectionQueue
explicitly. It will be created automatically. However, to properly clean up, you should call [ConnectionQueue releaseShared]
when the application quits, e.g. from applicationWillTerminate:
of your application delegate.
精彩评论