【问题标题】:How to make sure I have only 1 asynchronous NSURLConnection at a time?如何确保我一次只有 1 个异步 NSURLConnection?
【发布时间】:2011-08-07 08:07:29
【问题描述】:


我正在创建一个与服务器进行大量通信的应用程序。我想确保我一次只有 1 个连接 - 只有 1 个请求待处理。我希望如果我尝试发送另一个请求,它将等到当前请求完成后再发送下一个请求。

我该如何实现这个?
天呐!

【问题讨论】:

    标签: ios asynchronous request nsurlconnection


    【解决方案1】:

    我不知道有什么自动机制可以做到这一点。所以你必须自己写一个新类(我们称之为ConnectionQueue):

    基本上,不是直接创建NSURLConnection,而是调用ConnectionQueue 类(应该只有一个实例)的方法,将NSURLRequest 和委托作为参数。两者都被添加到队列中,即请求和代表的单独NSArray

    如果数组只包含一个元素,则没有未完成的请求,您可以使用指定的请求创建NSURLConnection。但是,不是将委托传递给方法,而是将 ConnectionQueue 实例作为委托传递。结果,连接队列将被告知连接的所有操作。在大多数情况下,您只需将回调转发给原始委托(您会在委托数组的第一个元素中找到它)。

    但是,如果未完成的连接完成(调用connection:didFailWithError:connectionDidFinishLoading:),您首先调用原始委托,然后从两个数组中删除连接。最后,如果数组不为空,则开始下一个连接。

    更新:

    这里有一些代码。它可以编译,但尚未经过其他测试。此外,NSURLConnectionDelegate 协议的实现是不完整的。如果您期望的不仅仅是已实现的回调,则必须添加它们。

    头文件:

    #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
    

    实施:

    #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
    

    要使用连接队列,请创建一个 NSURLRequest 实例,然后调用:

    [[ConnectionQueue sharedInstance] queueRequest:request delegate:self];
    

    无需显式创建ConnectionQueue 的单例实例。它将自动创建。但是,要正确清理,您应该在应用程序退出时调用[ConnectionQueue releaseShared],例如来自您的应用程序委托的applicationWillTerminate:

    【讨论】:

    • 我现在已经设法实现了这个,而且我写的差不多。只是有些疑惑/cmets:1. 保留 2 个数组和保留 1 个字典数组之间有区别吗? 2.在发送消息之前,您不应该检查代表是否回复了消息吗?我相信这是 NSURLConnection 3 的预期功能。有点笼统,并不特定于这段代码,但是 sharedInstance 方法是如何工作的?谁负责保存 sharedInstance,它存在于哪个块下?
    • 1.使用两个数组更实用,使用更少的内存。在这种情况下,字典很难看。如果您想要一个只有一个数组的干净解决方案,请实现一个包含请求和委托的特定类。 2. 是的,我应该检查一下代表是否回复了消息。另一种方法是实现一个类来拦截两个相关消息并转发所有剩余的消息,如stackoverflow.com/questions/3498158/…。 3.在答案底部查看我的更新。
    猜你喜欢
    • 1970-01-01
    • 2021-07-21
    • 1970-01-01
    • 1970-01-01
    • 2016-01-15
    • 1970-01-01
    • 1970-01-01
    • 2010-09-26
    • 1970-01-01
    相关资源
    最近更新 更多