Cocoa:使用相同的委托函数检查多个异步NSURLConnections是否需要?

Pla*_*mer 9 cocoa multithreading objective-c nsurlconnection

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

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

到目前为止,一切正常,但我不确定是否需要做任何事情以确保正确的"多线程"行为.

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

Jam*_*ald 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
}
Run Code Online (Sandbox Code Playgroud)


小智 13

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

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