iOS4にしたらNSOperationが動かなくなったときの解決法 | スマホアプリ開発記

スマホアプリ開発記

スマホアプリやサービス作りで感じたことを書いています。

iPhone SDK4.0になり、マルチスレッド関連にもかなりの変更が加えられました。その一つの影響として、NSOperationの仕様も変わっています。

何も考えずにisConcurrentをYESにして組んでいたアプリはiOS4では動かなくなる可能性があります

最も影響を受けるのは、NSURLConnectionによるHTTPリクエストをNSOperationを使っていた場合でしょう。NSURLConnectionをマルチスレッドで使うには、かなり丁寧に実装してあげないと動かなくなります。

手っ取り早いのはNSOperationQueueの生成を以下のように明示的にメインスレッドの呼び出しに変更することです。

// alloc,initは、iPhone3.xでisConcurrent=NOの時、およびiOS4では別スレッドで起動される
// iPhone3.xでisConcurrent=YESの時はメインスレッドで起動されていた
// NSOperationQueue *queue = [[[NSOperationQueue alloc] init] autorelease];

NSOperationQueue *queue = [NSOperationQueue mainQueue];

ただし、mainQueueはOS4.0以降のメソッドなので、OS3.xでは動かせません。そのため、OS3.xもサポートするアプリであれば、startメソッド内で以下のように強引にメインスレッドからの呼び出しにするのも、美しくはないですが単純で効果的でしょう。こちらは、以下の記事を参考にしました。

iOS4 Issue: NSURLConnection and NSOperation

- (void)start {
// 強制的にメインスレッドからstartを呼び出す
if (![NSThread isMainThread]) {
[self performSelectorOnMainThread:@selector(start) withObject:nil waitUntilDone:NO];
return;
}

if (![self isCancelled]) {
[NSURLConnection connectionWithRequest:request delegate:self];
}
}

いずれにせよ、上記は3.xで動いていたアプリを応急処置的にiOS4に対応させる方法で、根本的な解決はスレッドセーフなコードを書くことですね。

例:NSURLConnection in it's own thread