Tech Racho エンジニアの「?」を「!」に。
  • 開発

NSURLConnectionの同期通信でタイムアウトを設定したい(2)

前回の問題ですが、自己解決しました。

解決方法

今のメソッドを抜けずに現在のスレッドに溜まっている処理を処理するには、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などでコピーすると、メモリが解放されたときにエラーになったりするので、必要に応じてretainautoreleaseを行わないとダメですね。


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。