重複の可能性:
Grand Central Dispatch(GCD)とperformSelector-より適切な説明が必要
メインスレッドで「もの」を実行するには、_dispatch_async
_またはperformSelectorOnMainThread
を使用する必要がありますか?正しい/または間違った、および/またはベストプラクティスの好ましい方法はありますか?
例:_NSURLConnection sendAsynchronousRequest:urlRequest
_メソッドのブロック内でいくつかのロジックを実行しています。 UIAlertView
を表示するなど、メインビューに対して作業を行っているため、メインスレッドにUIAlertView
を表示する必要があります。これを行うために、私は次のコードを使用しています。
_[NSURLConnection sendAsynchronousRequest:urlRequest queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
// code snipped out to keep this question short
if(![NSThread isMainThread])
{
dispatch_async(dispatch_get_main_queue(), ^{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Oops!" message:@"Some Message" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
[alertView show];
});
}
}];
_
同じif(![NSThread isMainThread])
ステートメント内で、いくつかのカスタムメソッドも呼び出します。問題は、上記で使用している_dispatch_async
_メソッドを使用する必要があるのか、それとも代わりにperformSelectorOnMainThread
を使用する方がよいのかということです。たとえば、以下の完全なコード:
_[NSURLConnection sendAsynchronousRequest:urlRequest queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
// code snipped out to keep this question short
if(![NSThread isMainThread])
{
dispatch_async(dispatch_get_main_queue(), ^{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Oops!" message:@"Some Message" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
[alertView show];
// call custom methods in dispatch_async?
[self hideLoginSpinner];
});
// or call them here using performSelectorOnMainThread???
[self performSelectorOnMainThread:@selector(hideLoginSpinner) withObject:nil waitUntilDone:NO];
}
}];
_
参考までに-メインスレッドでこれらのアクションを実行しないと、UIAlertView
を表示するときに数秒の遅延が発生し、デバッガー_wait_fences: failed to receive reply: 10004003
_で次のメッセージが表示されます。これは、メインスレッドのUIを変更する必要があるためだとわかりました...誰かが私がやっていることをなぜやっているのか疑問に思っている場合に備えて...
Josh Caswellが提供するリンクで述べたように、この2つはほぼ同等です。最も顕著な違いは、performSelectorOnMainThread
はデフォルトの実行ループモードでのみ実行され、実行ループが追跡モードまたはその他のモードで実行されている場合に待機することです。ただし、コードの記述と保守にはいくつかの重要な違いがあります。
dispatch_async
には、コンパイラが通常のすべてのテストを実行するという大きな利点があります。 performSelectorOnMainThread
でメソッドを誤って入力すると、コンパイル時ではなく実行時に失敗します。dispatch_async
を使用すると、__block
修飾子を使用してメインスレッドからデータを簡単に返すことができます。dispatch_async
を使用すると、プリミティブ引数をオブジェクトでラップする必要がないため、処理がはるかに簡単になります。ただし、これには潜在的な落とし穴が伴います。一部のデータへのポインタがある場合は、ブロックキャプチャがデータをディープコピーしないことに注意してください。一方、performSelectorOnMainThread
に対して強制されるようにデータをオブジェクトにラップすると、ディープコピーが実行されます(特別なオプションを設定しない限り)。ディープコピーがないと、デバッグにイライラする断続的なバグに遭遇する可能性があります。つまり、char *
を呼び出す前に、dispatch_async
などをNSString
でラップする必要があります。