По дизайну, dispatch_*()
API не имеют понятия отмены. Причина этого заключается в том, что практически всегда верно, что ваш код поддерживает концепцию, когда остановиться или нет, и, таким образом, также поддерживая, что в API-интерфейсе dispatch _ *() будет избыточным (и при избыточности появятся ошибки).
Таким образом, если вы хотите «остановить раннее» или отменить ожидающие элементы в очереди отправки (независимо от того, как они были установлены в очередь), вы можете сделать это, разделив бит состояния с заблокированными блоками, что позволит вам Отмена.
if (is_canceled()) return;
Или:
__block BOOL keepGoing = YES;
dispatch_*(someQueue, ^{
if (!keepGoing) return;
if (weAreDoneNow) keepGoing = NO;
}
Обратите внимание, что оба enumerateObjectsUsingBlock:
и enumerateObjectsWithOptions:usingBlock:
оба поддерживают отмену, потому что API в другой роли. Вызов метода перечисления синхронный, даже если фактическое выполнение перечислимых блоков может быть полностью параллельным в зависимости от параметров.
Таким образом, установка *stopFlag=YES
сообщает, что перечисление останавливается. Однако он не гарантирует, что он немедленно остановится в параллельном случае. Перечисление может, по сути, выполнить еще несколько уже заблокированных блоков перед остановкой.
(Можно было бы подумать, что было бы разумнее вернуть BOOL
, чтобы указать, должно ли перечисление продолжаться. Для этого потребовалось бы, чтобы перечислимый блок выполнялся синхронно даже в параллельном случае, так что возвращаемое значение может быть проверено. Это было бы значительно менее эффективно.)
Ну, это не совсем так; в то время как это верно, что enumerateObjectsUsingBlock: является последовательным, есть также enumerateObjectsWithOptions: usingBlock :. Этот параметр «options» может использоваться для указания того, что перечисление должно происходить одновременно. Я не уверен, как они это делают внутренне, но я бы предположил, что это сделано с помощью диспетчера_группы, которая позволит более прямое управление. –
Но дело в том, что enumerateObjectsWithOptions: usingBlock: все еще имеет параметр * stop. –
Было бы логично поддерживать остановку в dispatch_apply(), но это не имело смысла в рамках целей дизайна. Утверждение о том, что флаг остановки в 'enumerateObjectsUsingBlock:' существует из-за предполагаемого последовательного выполнения, неверен; они полностью ортогональны. – bbum