2015-07-30 3 views
0

Мне нужно запустить method с block, несколько раз внутри for loop. Я также должен дождаться завершения всего выполнения blocks.ObjectiveC ожидание для блоков цикла с семафором

Моя проблема заключается в том, что я не могу понять, что я делаю неправильно, что заставляет мое приложение замораживаться. Вот код:

dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);//1 - creating semaphore 
for(int i = 0; i< myObj.count; i++){ 
      [[DataManager shared] verifyObjectId:myObj[i].id 
                completionBlock:^(BOOL found) { 
                 if(found){ 
                 //code here 
                 dispatch_semaphore_signal(semaphore);//3 - signaling semaphore to continue 
                 } 
                }]; 
     dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);//2 - getting semaphore to wait 
} 

//I want to continue once all DB checks complete 

Теперь, я не понимаю, почему semaphore не отпустит, а for loop не будет продолжаться.

Что мне действительно нужно, это для semaphore для освобождения после завершения всех проверок БД. В идеале я бы хотел, чтобы semaphore ждал за пределами for loop. Любые предложения о том, как это сделать?

EDIT: Решение: (на основе принятого ответа)

// create a group 
dispatch_group_t group = dispatch_group_create(); 
for(int i = 0; i< myObj.count; i++){ 
// pair a dispatch_group_enter for each dispatch_group_leave 
      dispatch_group_enter(group); 
      [[DataManager shared] verifyObjectId:myObj[i].id 
                completionBlock:^(BOOL found) { 
                 if(found){ 
                 //code here 
                 } 
                 dispatch_group_leave(group); //1 leave 
                }]; 
//Get a notification on a block that will be scheduled on the specified queue 
     dispatch_group_notify(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ 
       NSLog(@"-all done!-"); 
       //code here 
     }); 
} 

ответ

3

Без доступа к verifyObjectid:completiongBlock:, есть несколько вопросов. Во-первых, вы вызываете только dispatch_semaphore_signal, если верно found. Если found - все ложные, вы зашли в тупик. Это может быть просто ошибка транскрипции, и ваш реальный код может этого не сделать.

Еще одна догадка заключается в том, что блок завершения отправляется в очередь, в которой вы сейчас работаете (основная очередь?) Если это правда, то это определенно будет тупиком, потому что вы никогда не запустите dispatch_semaphore_signal, поскольку он ждет на dispatch_semaphore_wait. Я не могу сказать без информации о DataManager.

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

Лучшие инструменты для использования здесь: dispatch_apply и dispatch_group. Что-то вроде этого (непроверенные):

dispatch_group_t group = dispatch_group_create(); 
dispatch_apply(myObj.count, dispatch_get_global_queue(0, 0), ^(size_t i){ 
    dispatch_group_enter(group); 
    [[DataManager shared] verifyObjectId:myObj[i].id 
               completionBlock:^(BOOL found) { 
                if(found){ 
                 //code here 
                } 
                dispatch_group_leave(group)); 
               }]; 
}); 
dispatch_group_wait(group, DISPATCH_TIME_FOREVER); 

dispatch_apply не вернется, пока все блоки не завершили ход, а это значит, что dispatch_group_enter побежал «рассчитывать» раз. Затем вы используете dispatch_group_wait для ожидания всех вызовов до dispatch_group_leave.

+0

Я понимаю, что вы говорите. Я собираюсь экспериментировать с тем, что вы предлагаете. – nightfixed