2

私はGCD背景に行くものを持っています。GCDの終了中に読み込み待機画面をロードし、そのボタンで残りのコードを実行するボタンがあります。添付のサンプルです。

私の機能は動作しません。基本的には、GCDが完了するまで待機し、その間に待機メッセージをロードして、コードを続行します。

ありがとうございました

- (IBAction)btnTapped:(id)sender
{
    shouldCancel=NO;
    dispatch_queue_t existingQueque = dispatch_get_main_queue();//finds the current GCD, the one I created in a different method
    dispatch_group_t group =dispatch_group_create();

    dispatch_group_async(group, existingQueque, ^
    {
        dispatch_group_wait(group, DISPATCH_TIME_FOREVER);//does not work, I guess group can't be created here.
        [self performSelectorOnMainThread:@selector(showWaitViewWithMessage:) withObject:@"Loading" waitUntilDone:YES];//load this until GCD queque done

        [self performSelector:@selector(performSearch) withObject:nil afterDelay:0];
    });    
}
4

2 に答える 2

5

いくつかの考え:

  1. dispatch_get_main_queue()「別の方法で作成した現在のGCDを見つける」ことを提案します。いいえ、これはメインキュー(使用するとユーザーインターフェイスをブロックするキュー)を取得するだけであり、を介して他の場所で作成したキューは取得しませんdispatch_create_queue。はdispatch_get_main_queue()メインキューを取得するだけで、検索が行われている間、UIはブロックされます(たとえばUIActivityIndicatorView、スピンしません)。

  2. 大量のタスクをバックグラウンドキューにディスパッチした場合、それらすべてが終了するのを待ちたい場合は、dispatch_group_tまたはを使用dispatch_barrierしますが、表示されているものを考えると、それは必要ありません(1つしかありません)ディスパッチされた操作)、あなたはそこに行く必要はありません。ちなみに、グローバルキューを使用している場合、バリアは推奨されません。

  3. 単一のGCDバックグラウンドタスクの一般的なパターンは、質問が示唆するよりも単純です。(a)UIを更新して「読み込み中」と表示し、UIActivityIndicatorViewまたはそのようなものを表示します。これにより、ユーザーは、アプリが何かに取り組んでいることを示す、よりリッチなUXを利用できます。(b)バックグラウンドで検索をディスパッチします。(c)完了したら、UIアップデートをメインキューにディスパッチします。したがって、一般的なパターンは次のとおりです。

    - (IBAction)btnTapped:(id)sender
    {
        dispatch_queue_t backgroundQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
        // or, if you've already created you own background queue just use that here, 
        // or just create one here. But don't use dispatch_get_main_queue, as that 
        // won't use a background queue.
        //
        // dispatch_queue_t backgroundQueue = dispatch_queue_create("org.yourdomain.yourapp.search", NULL);
    
        [self showWaitViewWithMessage:@"Loading"];
    
        dispatch_async(backgroundQueue, ^{
            [self performSearch];             // do this in the background
            dispatch_async(dispatch_get_main_queue(), ^{
                [self updateUiAfterSearch];   // when done, dispatch UI update back to main queue
            });
        });
    
        // if you created a queue, remember to release it
        //
        // dispatch_release(backgroundQueue); 
    }
    
  4. 余談ですが、あなたperformSelectorOnMainThreadの中には、理由はありませんwaitUntilDone。やむを得ない理由がない限り、待たないでください。上記のように、この構成はまったく必要ありませんが、参考までに必要です。

  5. ちなみに、多くのサーバーは、特定のクライアントが一度に行うことができる同時リクエストの数に制限を課していることを知っておくことが重要です。複数のリクエストを開始している可能性がある場合(たとえば、ユーザーがボタンをタップし、サーバーの応答が遅い場合)、これにより、それらを同時に実行できます。このシナリオでは、NSOperationQueueを設定できる場所を追求する価値がありますmaxConcurrentOperationCountNSOperationQueueメソッドのブロックバージョン( addOperationWithBlockGCDではなくdispatch_async)を使用する場合、コードは同じ方法で構造化できますが、バックグラウンド操作の数を制限できます。

    また、NSOperationQueue操作間の依存関係を簡単に確立する機能を提供します(たとえばNSOperation、他のすべての終了に依存する完了)。私はそれを概説することができますが、あなたが投稿したコードはそれを必要としないので、あなたがそれがどのように見えるかを見たいと私に知らせない限り、私はあなたにそれを惜しまないでしょう。

于 2012-12-28T05:19:16.540 に答える
1

作成したキューを保存する必要があります。毎回作成しないでください。一度に1つだけ必要な場合は、シリアルキューを使用してください


 @implementation DDAppDelegate {
     dispatch_queue_t queue;
 }

 - (void)applicationDidFinishLaunching:(NSNotification *)aNotification
 {
     [self do];
     [self performSelector:@selector(do) withObject:nil afterDelay:1];
 }

 - (void)do {
     if(!queue)
         queue = dispatch_queue_create("com.example.MyQueue", NULL);

     dispatch_async(queue, ^{
         //serialized
         NSLog(@"1");
         sleep(10);
     });
 }
 @end

同時キューが必要な場合は、グローバルキューとdispatch_barrier_asyncを使用してください

@implementation DDAppDelegate

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    [self do];
    [self performSelector:@selector(do) withObject:nil afterDelay:1];
}

- (void)do {
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);

    dispatch_barrier_async(queue, ^{
        //serialized
        NSLog(@"1");
        sleep(10);
    });
}
于 2012-12-27T23:48:10.603 に答える