Por diseño, dispatch_*()
API no tienen noción de cancelación. La razón de esto es porque es casi universalmente cierto que su código mantiene el concepto de cuándo detener o no y, por lo tanto, también admite que en el despacho _ *() las API serían redundantes (y, con redundancia, vienen los errores).
Por lo tanto, si desea "detenerse antes" o cancelar los elementos pendientes en una cola de envío (independientemente de cómo fueron en cola), puede hacerlo compartiendo un poco de estado con los bloques en cola que le permiten cancelar.
if (is_canceled()) return;
O:
__block BOOL keepGoing = YES;
dispatch_*(someQueue, ^{
if (!keepGoing) return;
if (weAreDoneNow) keepGoing = NO;
}
Tenga en cuenta que tanto enumerateObjectsUsingBlock:
y enumerateObjectsWithOptions:usingBlock:
tanto cancelación de apoyo debido a que la API está en un papel diferente. La llamada al método de enumeración es sincrónica, incluso si la ejecución real de los bloques enumeradores puede ser totalmente simultánea dependiendo de las opciones.
Por lo tanto, establecer *stopFlag=YES
le indica a la enumeración que se detenga. Sin embargo, no garantiza que se detendrá inmediatamente en el caso concurrente. La enumeración puede, de hecho, ejecutar unos cuantos bloques ya en cola antes de detenerse.
(Se podría pensar brevemente que sería más razonable devolver BOOL
para indicar si la enumeración debería continuar. Hacerlo habría requerido que el bloque de enumeración se ejecutara sincrónicamente, incluso en el caso concurrente, de modo que el valor de retorno podría comprobarse. Esto hubiera sido mucho menos eficiente.)
Bueno, eso no es del todo cierto; Si bien es cierto que enumerateObjectsUsingBlock: es secuencial, también hay enumerateObjectsWithOptions: usingBlock :. Ese parámetro de "opciones" se puede usar para indicar que la enumeración debe realizarse al mismo tiempo. No estoy seguro de cómo lo están haciendo internamente, pero supongo que se hace usando un dispatch_group que permitiría un control más directo. –
Pero el punto es que enumerateObjectsWithOptions: usingBlock: todavía tiene el parámetro * stop. –
Sería lógico admitir detenerse en dispatch_apply(), pero no tenía sentido dentro de los objetivos de diseño. Declarar que la bandera de detención en 'enumerateObjectsUsingBlock:' existe debido a la ejecución secuencial implícita es incorrecta; los dos son completamente ortogonales. – bbum