2013-02-25 128 views
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

相反紡紗在一個循環中,等待計數器等於零,每次遞減它的時候檢查計數器值的,那麼當它達到零觸發事件。

-(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:上的每個索引。

1

您可以使用這些來同步使用。

GCDthis

performSelector:waitUntilDone:YES

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

哦......我沒有說清楚這一點。那叫做synchronizeItemImage方法通過RESTKit啓動一個異步請求。因此,執行異步方法或'waitUntilDone:'可能無效。爲了避免減少不同線程中的共享內存,我可以在串行調度隊列中從Chris Devereux的解決方案執行該塊,或者這也不好? – Obenland 2013-02-25 18:56:29

+0

哦。在這種情況下,只要在主線程上調用完成處理程序,就可以減少一些變量。或者更好的是,在你的windowController或應用程序委託上遞減一個屬性,並使用KVO通知來找出它何時到達零。 – iluvcapra 2013-02-25 19:28:55