14

重複の可能性:
Grand Central Dispatch (GCD) と performSelector - より詳しい説明が必要

メインスレッドで「もの」を実行するには、またはを使用する必要がありますdispatch_asyncperformSelectorOnMainThread? 好ましい方法、正しい/または間違っている、および/またはベストプラクティスはありますか?

例: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 を変更する必要があるためであることがわかりました。

4

1 に答える 1

14

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

  1. dispatch_asyncコンパイラがすべての通常のテストを行うという大きな利点があります。メソッドのタイプを間違えるとperformSelectorOnMainThread、コンパイル時ではなく実行時に失敗します。
  2. dispatch_async__block修飾子を使用してメインスレッドからデータを返すのがはるかに簡単になります。
  3. dispatch_asyncプリミティブ引数をオブジェクトでラップする必要がないため、プリミティブ引数の処理がはるかに簡単になります。ただし、これには潜在的な落とし穴があります。一部のデータへのポインタがある場合、ブロック キャプチャはデータをディープ コピーしないことに注意してください。一方、performSelectorOnMainThread(特別なオプションを設定しない限り) ディープ コピーを実行するために強制されるように、データをオブジェクトにラップします。ディープ コピーがないと、断続的なバグが発生し、デバッグが煩わしくなります。つまり、を呼び出す前にchar *in のようにラップする必要があります。NSStringdispatch_async
于 2012-07-17T23:02:17.743 に答える