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();
            }
       }];
    }
 }

为了解释为什么感觉不对,你在这里做两件事,你应该永远不要或很少做:

  • 使用后台队列。这是困难且容易出错的。如果没有阅读大量有关编写并发代码的内容,请不要这样做。如果一个操作阻塞了相当长的时间(例如,从磁盘读取文件,或执行密集计算),您也只需要这样做。不要假设你需要这样做,除非你有充分的理由(例如,一个可衡量的性能问题)。

  • 循环旋转,检查变量的变化并调用睡眠。你不应该这样做。

此外,如果您要遍历数组中的元素,则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 回答