ユーザーが UI を操作している場合でもデータを取得できるように、Three20 ライブラリを拡張して、複数のスレッドにまたがる非同期接続を実装しました。CFNetwork フレームワーク内で検出されたランダムなメモリ リークを何時間も追跡した後、最終的に root が問題を引き起こしました。ときどき、応答とデータを見失っていました。
複数のスレッドがアクセスするデータ構造は、適切なロックで保護する必要があります。相互に排他的な方法で共有データ構造にアクセスするためにロックを使用していない場合、スレッドセーフではありません。Apple のThreading Programming Guideの「 Using Locks 」セクションを参照してください。
最善の解決策は、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
}