web-dev-qa-db-ja.com

dispatch_asyncまたはperformSelectorOnMainThreadを使用してメインスレッドでUIの変更を実行しますか?

重複の可能性:
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を変更する必要があるためだとわかりました...誰かが私がやっていることをなぜやっているのか疑問に思っている場合に備えて...

14
ElasticThoughts

Josh Caswellが提供するリンクで述べたように、この2つはほぼ同等です。最も顕著な違いは、performSelectorOnMainThreadはデフォルトの実行ループモードでのみ実行され、実行ループが追跡モードまたはその他のモードで実行されている場合に待機することです。ただし、コードの記述と保守にはいくつかの重要な違いがあります。

  1. dispatch_asyncには、コンパイラが通常のすべてのテストを実行するという大きな利点があります。 performSelectorOnMainThreadでメソッドを誤って入力すると、コンパイル時ではなく実行時に失敗します。
  2. dispatch_asyncを使用すると、__block修飾子を使用してメインスレッドからデータを簡単に返すことができます。
  3. dispatch_asyncを使用すると、プリミティブ引数をオブジェクトでラップする必要がないため、処理がはるかに簡単になります。ただし、これには潜在的な落とし穴が伴います。一部のデータへのポインタがある場合は、ブロックキャプチャがデータをディープコピーしないことに注意してください。一方、performSelectorOnMainThreadに対して強制されるようにデータをオブジェクトにラップすると、ディープコピーが実行されます(特別なオプションを設定しない限り)。ディープコピーがないと、デバッグにイライラする断続的なバグに遭遇する可能性があります。つまり、char *を呼び出す前に、dispatch_asyncなどをNSStringでラップする必要があります。
14
torrey.lyons