等待许多异步调用执行回调

问题描述:

我想同步一些数据与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); 

但我认为这是一个相当不错的方法。有任何想法吗?

相反纺纱在一个循环中,等待计数器等于零,每次递减它的时候检查计数器值的,那么当它达到零触发事件。

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

要解释为什么感觉不对,有两件事情你在这里做什么,你应该做的或者从未或很少:

  • 使用背景队列。这很困难,容易出错。如果没有阅读关于编写并发代码的lot,请不要这样做。如果某个操作阻塞了相当长的时间(例如,从磁盘读取文件或执行强化计算),则也只需确实需要执行此操作。除非您有充分的理由(例如,可测量的性能问题),否则不要假设您需要这样做。

  • 旋转在一个循环中,检查一个变量的变化和调用睡眠。你应该从来没有做到这一点。

此外,如果你遍历在数组中的元素,所述语法for ... in是好得多(和可能更有效)调用objectAtIndex:上的每个索引。

您可以使用这些来同步使用。

GCDthis

performSelector:waitUntilDone:YES

永远不会像这样在不同的线程中检查或减少共享内存,它会导致竞争。使用派遣组来做你正在做的事情。

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); 
+0

哦......我没有说清楚这一点。那叫做synchronizeItemImage方法通过RESTKit启动一个异步请求。因此,执行异步方法或'waitUntilDone:'可能无效。为了避免减少不同线程中的共享内存,我可以在串行调度队列中从Chris Devereux的解决方案执行该块,或者这也不好? – Obenland 2013-02-25 18:56:29

+0

哦。在这种情况下,只要在主线程上调用完成处理程序,就可以减少一些变量。或者更好的是,在你的windowController或应用程序委托上递减一个属性,并使用KVO通知来找出它何时到达零。 – iluvcapra 2013-02-25 19:28:55