开发者

How to make sure I have only 1 asynchronous NSURLConnection at a time?

I'm creating an app which communicates alot with a server. I want to make sure I have only 1 connection at a time - only 1 request pending. I want so that if I try to send anothe开发者_开发百科r request, It will wait until the current one is finished before sending the next.

How can I implement This?

Tnx!


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜