2014-11-28 3 views
1

Например, у меня есть метод с тремя асинхронными блоками. Каждый результат блока необходим для выполнения следующего блока для достижения результата конечных методов. Итак, что я ищу хорошую стратегия НОДА для make'em выполнять в строгом порядке и без врезных замковДождитесь завершения блоков асинхронных блоков

__block id task1Result;  
__block id task2Result;  
__block id finalResult; 

[self startTask1:^(id result) { task1Result = result }] 

[self startTask2:task1Result block:^(id result) { task2Result = result }] 

[self startTask3:task2Result block:^(id result) { finalResult = result }] 

UPD. Я нашел решение:

dispatch_semaphore_t sem = dispatch_semaphore_create(0); 

__block id task1Result;  
__block id task2Result;  
__block id finalResult; 

[self startTask1:^(id result) { 
    task1Result = result; 
    dispatch_semaphore_signal(sem); 
}]; 
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER); 

[self startTask2:task1Result block:^(id result) { 
    task2Result = result; 
    dispatch_semaphore_signal(sem); 
}]; 
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER); 

[self startTask3:task2Result block:^(id result) { finalResult = result }]; 

Но в моем случае, я столкнулся с проблемой, с каким-то методом библиотеки, который приносит приложение к тупиковой ситуации. > <

+0

Не используйте семафоры. Это худшее возможное решение, так как оно может легко привести к инверсии приоритетов. Пожалуйста, используйте последовательную очередь для сериализации ваших операций. –

+0

Можете ли вы привести пример кода, как я должен использовать их в моем случае? –

+0

Создайте очередную очередь и отправьте свои блоки. Они будут исполняться по порядку. doggod дал вам пример ниже. –

ответ

3

Создание последовательной очереди отправки, как описано здесь:
https://developer.apple.com/library/ios/documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html

В двух словах:

dispatch_queue_t queue; 
queue = dispatch_queue_create("com.example.MyQueue", NULL); 
dispatch_async(queue, ^{ 
    printf("Do some work here.\n"); 
}); 
dispatch_async(queue, ^{ 
    printf("When finished do next task.\n"); 
}); 

Имейте в виду, что вы должны обрабатывать очередь нужно самостоятельно.

+0

Disput_queue хорош, но если он вызывает асинхронные API внутри dispatch_async, это не приблизит его к цели ожидания всех его вызовов API. –

+0

@Claus Jørgensen: очередь является серийной и будет заботиться о выполнении одной задачи за раз. Не могли бы вы объяснить, почему этого недостаточно? – dogsgod

+1

Если вы поместите 'dispatch_async (anotherQueue,^{})' в свой 'dispatch_async', он не будет ждать завершения. Предполагая, что его задача API является существующей, не построенной на GCD, ваше предложение не будет иметь никакого влияния. Дело сводится к тому, ссылается ли OP на существующий API или нет. –

-1

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

dispatch_group_t group = dispatch_group_create(); 
__block id result; 

dispatch_group_enter(group); 
[self startTask1:^(id task1Result) { 
    [self startTask2:task1Result block:^(id task2Result) { 
    [self startTask3:task2Result block:^(id finalResult) { 
     result = finalResult; 
     dispatch_group_leave(group); 
    }]; 
    }]; 
}]; 

dispatch_group_wait(group, DISPATCH_TIME_FOREVER); 

Одно осложнение вы можете столкнуться, является ли рискует тупик, то есть пытается епдиеие задачи из обработчика завершения, если ваши обработчики завершения вызываются на одной и той же последовательной очереди, которая обрабатывает enqueueing задачи.

+0

Этот путь слишком уродлив. Я хочу избавиться от него. –

+0

Вы считаете это уродливым в первую очередь из-за гнездования обработчиков завершения? – Pivot

Смежные вопросы