前回の問題ですが、自己解決しました。
解決方法
今のメソッドを抜けずに現在のスレッドに溜まっている処理を処理するには、NSRunLoopのrunを使えば良いということでした。
つまり、
[[NSRunLoop currentRunLoop]run];
とやれば、NSURLConnection
によって呼ばれるconnection
などが実行されます。
ただし、runは無限ループになって永久に処理し続ける(処理がなければ待っている)ので、別スレッドで実行して、目的を達成したらスレッドごと終了してしまう必要があります。
そこで、別スレッドでNSURLConnectionのconnectionWithRequest
を実行し、そのスレッド内でNSRunLoop
のrunを実行します。
そして、親スレッドでwhileループで監視しつつ、responseが返ってきたらスレッドを破棄すればOKです。
実際のコード
コードにしてみると以下のような感じです。
@implementation TestConnector
// これを外部から呼ぶ
- (NSString *)sendRequest:(NSString *)url {
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[request setTimeoutInterval:3.0]; //3秒で反応長ければエラーにする
//別スレッドで接続
_response = nil; //_responseはvolatile指定したインスタンス変数
NSThread *th = [[NSThread alloc]initWithTarget:self selector:@selector(sendRequestThread:) object:request];
[th start];
//responseが取得できるまで待つ
while (_response == nil) {
[NSThread sleepForTimeInterval:0.1];
NSLog(@"sleep...");
}
[th cancel];
[th release];
[request release];
return _response;
}
// リクエストを送信し、受信が完了するまで待つスレッド
- (void)sendRequestThread:(NSURLRequest *)request {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
//接続し、受信完了まで無限ループを回す
[NSURLConnection connectionWithRequest:request delegate:self];
[[NSRunLoop currentRunLoop]run];
[connection release]; //実際には↑が無限ループなので呼ばれないはず
[pool drain];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
//データの保存処理などを行う
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
//ここで適切に_responseをセットする
_response = @"おわったよ";
}
@end
手抜きしたので、メモリリークがあるかも知れません。
実際には、responseは何らかのオブジェクトになると思います。
その際は、単にconnectionDidFinishLoading
などでコピーすると、メモリが解放されたときにエラーになったりするので、必要に応じてretain
とautorelease
を行わないとダメですね。