4

一部のデータをWebサービスと同期させたい。アイテムごとに、非同期呼び出しを行う必要があります。

各アイテムが同期されたときに、完了ブロックの魔女が呼び出されるようにしたいです。アイテムごとに、完了ブロックを実行できます。今、私はそれを行うための良い方法を知りません。

これはインターフェースです:

-(void) synchronizeItemsOnComplete:(CompleteBlock) block {
    NSArray* items = // get items
    for (int i = 0, n = [items count]; i < n; i++) {
       [self synchronizeItem:[items objectAtIndex:i] onComplete:^{
          // What do do here?
       }];
    }
    // And/or here?
}

-(void) synchronizeItemOnComplete:(CompleteBlock) block {
    // do something
    block();
}

同期を待ってからブロックを実行するにはどうすればよいですか?

私はこのようなことを試みました:

NSArray* items = // get items

__block int countOfItemsUntilDone = [items count];

for (int i = 0, n = countOfItemsUntilDone; i < n; i++) {
    [self synchronizeItem:[items objectAtIndex:i] onComplete:^{
        countOfItemsUntilDone--;
    }];
}

dispatch_queue_t queue = dispatch_queue_create("wait for syncing", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
    while (countOfItemsUntilDone > 0) {
        usleep(1000); // wait a little bit
    }
    block();
});
dispatch_release(queue);

しかし、これはかなり悪い方法だと思います。何か案は?

4

3 に答える 3

4

カウンターがゼロになるのを待つループで回転する代わりに、カウンター値をデクリメントするたびにチェックし、ゼロに達したときにイベントを発生させます。

 -(void) synchronizeItemsOnComplete:(CompleteBlock) block {
    NSArray* items = // get items
    __block NSUInteger remaining = [items count];

    for (ItemClass* item in items) {
       [self synchronizeItemImage:item onComplete:^{
            --remaining;
            if (remaining == 0) {
                block();
            }
       }];
    }
 }

なぜそれが間違っていると感じるのかを説明するために、ここで行っていることは2つあり、決してまたはめったに行うべきではありません。

  • バックグラウンドキューの使用。これは難しく、バグが発生しやすいです。並行コードの記述について多くを読まずにそれをしないでください。また、これを実際に行う必要があるのは、操作がかなりの時間ブロックされた場合(たとえば、ディスクからファイルを読み取ったり、集中的な計算を実行したりする場合)だけです。正当な理由(たとえば、測定可能なパフォーマンスの問題)がない限り、それを行う必要があると思い込まないでください。

  • ループで回転し、変数の変更をチェックし、スリープを呼び出します。これは絶対にしないでください。

また、配列内の要素をループしている場合、for ... in各インデックスでobjectAtIndex:を呼び出すと、構文がはるかに優れた(そして潜在的により効率的に)なります。

于 2013-02-25T17:02:44.927 に答える
2

このように異なるスレッドの共有メモリをチェックまたはデクリメントしないでください。競合が発生する可能性があります。ディスパッチグループを使用して、実行していることを実行します。

dispatch_queue_t myBGQueue;
dispatch_group_t itemsGroup = dispatch_group_create();

for (ItemClass *item in items) {
    dispatch_group_async(itemsGroup, myBGQueue, ^{
        [self synchronizeItemImage:item];
    });
}

/* execution will sleep here until all the blocks added in the `for` complete */
dispatch_group_wait(itemsGroup, DISPATCH_TIME_FOREVER);

dispatch_release(itemsGroup);
于 2013-02-25T18:44:04.613 に答える
1

これらを使用して同期的に使用できます。

GCDこれ

performSelector:waitUntilDone:YES

于 2013-02-25T16:37:58.110 に答える