2013-02-25 2 views
4

Я хочу синхронизировать некоторые данные с веб-службой. Для каждого элемента я должен выполнить асинхронный вызов.Ждите много асинхронных вызовов для выполнения обратного вызова

Я хочу, чтобы был завершен блок завершения, когда каждый элемент был синхронизирован. Для каждого элемента я могу выполнить блок завершения. Теперь я не знаю, как это сделать.

Это интерфейс:

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

Чтобы объяснить, почему он чувствует себя не так, есть две вещи, которые вы здесь делаете, что вы не должны делать, либо никогда или редко:

  • Использование фоновых очередей. Это сложно и сложно. Не делайте этого, не читая лот о написании параллельного кода. Вам также действительно нужно это делать, если операция блокируется в течение значительного времени (например, для чтения файла с диска или для интенсивного вычисления). Не предполагайте, что вам нужно это сделать, если у вас нет веской причины (например, измеримая проблема с производительностью).

  • Вращение в петле, проверка переменной на изменения и вызов сна. Вы должны никогда сделайте это.

Кроме того, если вы цикл над элементами в массиве, синтаксис for ... in гораздо лучше (и потенциально более эффективный), призывающая objectAtIndex: по каждому индексу.

1

Их можно использовать синхронно.

GCD и this

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. Таким образом, для выполнения этого метода async или с 'waitUntilDone:' вероятно, не получится. Чтобы избежать уменьшения количества разделяемой памяти в разных потоках, я мог бы выполнить блок из решения Криса Деверо в очереди последовательной отправки или это тоже плохо? – Obenland

+0

Ох. В этом случае, пока обработчики завершения вызываются в основном потоке, вы можете просто уменьшить некоторую переменную. Или лучше, уменьшите свойство на своем windowController или делегировании приложения и используйте уведомления KVO, чтобы узнать, когда он достигнет нуля. – iluvcapra