我增强了 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
}