Есть ли способ моделировать a break
оператор в a dispatch_apply()
блок?
Например, каждое Какао API, я видел контакт с перечислением блоков, имеет параметр "остановки":
[array enumerateObjectsUsingBlock:^(id obj, NSUInteger i, BOOL *stop) {
if ([obj isNotVeryNice]) {
*stop = YES; // No more enumerating!
} else {
NSLog(@"%@ at %zu", obj, i);
}
}];
Действительно ли там что-то подобно для GCD?
По замыслу dispatch _ * ()
API не имеют понятия отмены. Причина этого в том, что почти всегда верно, что ваш код поддерживает концепцию того, когда остановиться или нет, и, таким образом, также поддерживает то, что в диспетчере _ * () API-интерфейсы будут избыточными (а с избыточностью возникают ошибки).
Таким образом, если вы хотите «остановить раньше» или иным образом отменить ожидающие элементы в очереди отправки (независимо от того, как они были поставлены в очередь), вы делаете это, разделяя некоторый бит состояния с помещенными в очередь блоками, что позволяет вам отменить .
if (is_canceled()) return;
Или:
__block BOOL keepGoing = YES;
dispatch_*(someQueue, ^{
if (!keepGoing) return;
if (weAreDoneNow) keepGoing = NO;
}
Обратите внимание, что оба enumerateObjectsUsingBlock:
и enumerateObjectsWithOptions: usingBlock:
поддерживают отмену, поскольку этот API выполняет другую роль. Вызов метода перечисления является синхронным , даже если фактическое выполнение блоков перечисления может быть полностью параллельным, в зависимости от опций.
Таким образом, установка * stopFlag = YES
указывает на остановку перечисления. Однако это не гарантирует немедленного прекращения работы в параллельном случае. Фактически перед остановкой перечисление может выполнить еще несколько блоков, уже поставленных в очередь.
(Вкратце можно подумать, что было бы более разумным вернуть BOOL
, чтобы указать, следует ли продолжать перечисление. Для этого потребовалось бы, чтобы блок перечисления выполнялся синхронно, даже в параллельном случае, чтобы можно было проверить возвращаемое значение, что было бы намного менее эффективно.)
Вы не можете нарушить
dispatch_apply
, поскольку это нелогично.
В -enumerateObjectsUsingBlock:
разрыв четко определен, потому что функции выполняются последовательно . Но в dispatch_apply
функции выполняются параллельно. Это означает, что при i = 3
-м вызове «блока» мог быть начат i = 4
-й вызов. Если вы прервите
на i = 3
, должен ли вызов i = 4
по-прежнему выполняться?
@BJ - самый близкий ответ, который вы можете сделать, но всегда будут какие-то «переливы».
Я не думаю, что dispatch_apply поддерживает это. Лучший способ, который я могу придумать, - это создать логическую переменную __block и проверить ее в начале блока. Если он установлен, быстро спасайтесь. Вам все равно придется прогонять блок через остальные итерации, но это будет быстрее.