¿Alternativas a dispatch get current queue () para bloques de finalización en iOS 6?


Tengo un método que acepta un bloque y un bloque de finalización. El primer bloque debe ejecutarse en segundo plano, mientras que el bloque de finalización debe ejecutarse en cualquier cola al que se haya llamado el método.

Para este último siempre usé dispatch_get_current_queue(), pero parece que está obsoleto en iOS 6 o superior. ¿Qué debo usar en su lugar?

Author: JOM, 2012-11-05

7 answers

El patrón de "ejecutar en cualquier cola en la que estaba la persona que llamó" es atractivo, pero en última instancia no es una gran idea. Esa cola podría ser una cola de baja prioridad, la cola principal o alguna otra cola con propiedades impares.

Mi enfoque favorito para esto es decir "el bloque de finalización se ejecuta en una cola definida por implementación con estas propiedades: x, y, z", y dejar que el bloque se envíe a una cola en particular si el llamante quiere más control que eso. Un conjunto típico de propiedades a especificar sería algo así como "serial, non-reentrant, and async with respect to any other application-visible queue".

* * EDITAR * *

Catfish_Man puso un ejemplo en los comentarios a continuación, solo lo estoy agregando a su respuesta.

- (void) aMethodWithCompletionBlock:(dispatch_block_t)completionHandler     
{ 
    dispatch_async(self.workQueue, ^{ 
        [self doSomeWork]; 
        dispatch_async(self.callbackQueue, completionHandler); 
    } 
}
 62
Author: Catfish_Man,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-02-04 22:07:18

Este es fundamentalmente el enfoque incorrecto para la API que está describiendo. Si una API acepta un bloque y un bloque de finalización para ejecutarse, los siguientes hechos deben ser verdaderos:

  1. El" bloque a ejecutar " debe ejecutarse en una cola interna, por ejemplo, una cola que sea privada para la API y, por lo tanto, totalmente bajo el control de esa API. La única excepción a esto es si la API declara específicamente que el bloque se ejecutará en la cola principal o en uno de los concurrentes globales cola.

  2. El bloque de finalización debe siempre expresarse como una tupla (cola, bloque) a menos que las mismas suposiciones que para #1 se mantengan verdaderas, por ejemplo, el bloque de finalización se ejecutará en una cola global conocida. Además, el bloque de finalización debe ser enviado async en la cola pasada.

Estos no son solo puntos estilísticos, son totalmente necesarios para que su API esté a salvo de bloqueos u otro comportamiento de casos extremos que de lo contrario lo colgará el árbol más cercano algún día. :-)

 24
Author: jkh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-11-11 02:27:29

Las otras respuestas son grandes, pero para el yo la respuesta es estructural. Tengo un método como este que está en un Singleton:

- (void) dispatchOnHighPriorityNonMainQueue:(simplest_block)block forceAsync:(BOOL)forceAsync {
    if (forceAsync || [NSThread isMainThread])
        dispatch_async_on_high_priority_queue(block);
    else
        block();
}

Que tiene dos dependencias, que son:

static void dispatch_async_on_high_priority_queue(dispatch_block_t block) {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), block);
}

Y

typedef void (^simplest_block)(void); // also could use dispatch_block_t

De esa manera centralizo mis llamadas a dispatch en el otro hilo.

 14
Author: Dan Rosenstark,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-12 23:30:45

Debe tener cuidado con su uso de dispatch_get_current_queue en primer lugar. Desde el archivo de cabecera:

Recomendado solo para fines de depuración y registro:

El código no debe hacer ninguna suposición sobre la cola devuelta, a menos que es una de las colas globales o una cola que el propio código ha creado. El código no debe asumir que la ejecución síncrona en una cola es a salvo de punto muerto si esa cola no es la devuelta por dispatch_get_current_queue ().

Puedes hacer una de dos cosas:

  1. Mantenga una referencia a la cola en la que publicó originalmente (si la creó a través de dispatch_queue_create), y use eso a partir de entonces.

  2. Utilice colas definidas por el sistema a través de dispatch_get_global_queue, y mantenga un registro de cuál está utilizando.

Efectivamente, mientras que anteriormente confiaba en el sistema para realizar un seguimiento de la cola en la que se encuentra, va a tener que hacerlo usted mismo.

 11
Author: WDUK,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-11-05 18:18:39

Para aquellos que todavía necesitan comparar en cola, puede comparar colas por su etiqueta o especificaciones. Compruebe esto https://stackoverflow.com/a/23220741/1531141

 4
Author: alexey.hippie,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:32:20

Apple había dejado en desuso dispatch_get_current_queue(), pero dejó un agujero en otro lugar, por lo que todavía podemos obtener la cola de despacho actual:

if let currentDispatch = OperationQueue.current?.underlyingQueue {
    print(currentDispatch)
    // Do stuff
}

Esto funciona al menos para la cola principal. Tenga en cuenta que la propiedad underlyingQueue está disponible desde iOS 8.

Si necesita realizar el bloque de finalización en la cola original, también puede usar OperationQueue directamente, quiero decir sin GCD.

 2
Author: kelin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-07-31 08:36:04

Esta es una respuesta yo también. Así que voy a hablar de nuestro caso de uso.

Tenemos una capa de servicios y la capa de interfaz de usuario (entre otras capas). La capa de servicios ejecuta tareas en segundo plano. (Tareas de manipulación de datos, tareas de CoreData, llamadas a la red, etc.). La capa de servicio tiene un par de colas de operación para satisfacer las necesidades de la capa de interfaz de usuario.

La capa de interfaz de usuario depende de la capa de servicios para hacer su trabajo y luego ejecutar un bloque de finalización exitosa. Este bloque puede tener código UIKit. Simple el caso de uso es obtener todos los mensajes del servidor y recargar la vista de colección.

Aquí garantizamos que los bloques que se pasan a la capa de servicios se envían a la cola en la que se invocó el servicio. Dado que dispatch_get_current_queue es un método obsoleto, usamos el NSOperationQueue.currentQueue para obtener la cola actual de la persona que llama. Nota importante sobre esta propiedad.

Llamando a este método desde fuera del contexto de una operación en ejecución normalmente resultados de nil ser devueltos.

Dado que siempre invocamos nuestros servicios en una cola conocida (Nuestras colas personalizadas y la cola Principal), esto funciona bien para nosotros. Tenemos casos en los que ServiceA puede llamar a ServiceB, que puede llamar a ServiceC. Dado que controlamos desde dónde se realiza la primera llamada de servicio, sabemos que el resto de los servicios seguirán las mismas reglas.

So NSOperationQueue.currentQueue siempre devolverá una de nuestras Colas o el mainQueue.

 0
Author: Kris Subramanian,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-04-03 22:55:39