9

这是参考 StackOverflow 问题管理多个异步 NSURLConnection 连接

我同时发出多个异步 HTTP 请求。所有这些都使用相同的 NSURLConnection 委托函数。(如上面另一个问题中所指定的,每个连接的 receivedData 对象都不同。在委托中,我解析了 receivedDate 对象,并对这些解析的字符串执行其他操作)

到目前为止,一切对我来说都很好,但我不确定是否需要做任何事情来确保正确的“多线程”行为。

  • 是否有可能有两个以上的连接同时使用委托?(我认为是的)
  • 如果是,如何解决?(可可会自动执行此操作吗?)
  • 我是否需要进行额外检查以确保“正确”处理每个请求?
4

3 回答 3

19

我增强了 Three20 库以实现跨多个线程的异步连接,以便即使用户正在使用 UI 也能获取数据。经过数小时的追查在 CFNetwork 框架中检测到的随机内存泄漏,我终于找到了问题的根源。我偶尔会忘记响应和数据。

由多个线程访问的任何数据结构都必须由适当的锁保护。如果您不使用锁以互斥方式访问共享数据结构,那么您就不是线程安全的。请参阅 Apple线程编程指南的“使用锁”部分。

最好的解决方案是继承 NSURLConnection 并添加实例变量来存储其关联的响应和响应数据。然后在每个连接委托方法中,您将 NSURLConnection 强制转换为您的子类并访问这些实例变量。这保证是互斥的,因为每个连接都将与其自己的响应和数据捆绑在一起。我强烈建议尝试这个,因为它是最干净的解决方案。这是我的实现中的代码:

@interface TTURLConnection : NSURLConnection {
 NSHTTPURLResponse* _response;
 NSMutableData* _responseData;
}

@property(nonatomic,retain) NSHTTPURLResponse* response;
@property(nonatomic,retain) NSMutableData* responseData;

@end

@implementation TTURLConnection

@synthesize response = _response, responseData = _responseData;

- (id)initWithRequest:(NSURLRequest *)request delegate:(id)delegate {
 NSAssert(self != nil, @"self is nil!");

 // Initialize the ivars before initializing with the request
    // because the connection is asynchronous and may start
    // calling the delegates before we even return from this
    // function.

 self.response = nil;
 self.responseData = nil;

 self = [super initWithRequest:request delegate:delegate];
 return self;
}

- (void)dealloc {
 [self.response release];
 [self.responseData release];

 [super dealloc];
}

@end

/////////////////////////////////////////////////////////////////
////// NSURLConnectionDelegate

- (void)connection:(NSURLConnection*)connection
didReceiveResponse:(NSHTTPURLResponse*)response {
 TTURLConnection* ttConnection = (TTURLConnection*)connection;
 ttConnection.response = response;
 ttConnection.responseData = [NSMutableData
                                 dataWithCapacity:contentLength];
}

- (void)connection:(NSURLConnection*)connection
    didReceiveData:(NSData*)data {
 TTURLConnection* ttConnection = (TTURLConnection*)connection;
 [ttConnection.responseData appendData:data];
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
 TTURLConnection* ttConnection = (TTURLConnection*)connection;

    if (ttConnection.response.statusCode == 200) {
        // Connection success
    }
}

- (void)connection:(NSURLConnection *)connection
  didFailWithError:(NSError *)error {  
    TTURLConnection* ttConnection = (TTURLConnection*)connection;
    // Handle the error
}
于 2009-12-21T05:39:11.033 回答
13

假设您在单个线程上启动所有(异步)连接,那么委托消息将全部发布在该线程的运行循环中。因此,委托只需要能够同时处理一条正在处理的消息;运行循环将一次传递一条消息。这意味着虽然委托消息的顺序是未知的,并且下一条消息可能来自任何连接对象,但您的委托方法不会并发执行。

但是,如果您实际上尝试跨多个线程使用相同的委托对象,而不仅仅是使用 API 的异步特性,那么您需要处理并发委托方法。

于 2009-07-28T07:16:56.647 回答
0

是的,可以有多个连接。通知对象包含一个指向NSURLConnection触发通知的指针。

在内部,我猜想NSURLConnection监听一个套接字并在它准备好数据时执行类似的操作。

[your_delegate 
    performSelectorOnMainThread:@selector(connectionCallback:) 
    withObject:self 
    waitUntilDone:NO];

所以你不必担心它是多线程的,NSURLConnection会照顾好这个。为简单起见,我写了自我,在现实世界NSNotification中给出了一个对象。

您不必进行任何与多线程相关的检查。

于 2009-07-28T07:55:05.917 回答