45

He usado tanto GCD como performSelectorOnMainThread: waitUntilDone en mis aplicaciones, y tiendo a pensar que son intercambiables, es decir, performSelectorOnMainThread: waitUntilDone es un Obj -C wrapper a la sintaxis de GCD C. He estado pensando en estos dos comandos como equivalentes:Grand Central Dispatch (GCD) vs. performSelector - necesita una mejor explicación

dispatch_sync(dispatch_get_main_queue(), ^{ [self doit:YES]; }); 


[self performSelectorOnMainThread:@selector(doit:) withObject:YES waitUntilDone:YES]; 

Am I incorrecto? Es decir, ¿hay alguna diferencia entre los comandos de performSelector * y los de GCD? He leído mucha documentación sobre ellos, pero todavía tengo que ver una respuesta definitiva.

+5

withObject: SÍ no funcionaría y debería darle al menos una advertencia. Lo cual podría ser una ventaja de GDC, donde puede enviar argumentos arbitrarios a un receptor. – FelixLam

+0

Bien, tendría que envolverlo en un NSNumber. Pero, ignorando esa parte, ¿hay algo más que sea diferente? Buen punto, sin embargo. – akaru

Respuesta

20

performSelectorOnMainThread: hace no usa GCD para enviar mensajes a objetos en el hilo principal.

Así es como el documentation dice que el método se implementa:

- (void) performSelectorOnMainThread:(SEL) selector withObject:(id) obj waitUntilDone:(BOOL) wait { 
    [[NSRunLoop mainRunLoop] performSelector:selector target:self withObject:obj order:1 modes: NSRunLoopCommonModes]; 
} 

Y en performSelector:target:withObject:order:modes:, los estados de documentación:

Este método establece un temporizador para llevar a cabo el mensaje aSelector en el hilo actual ejecutar bucle al comienzo de la siguiente iteración de bucle de ejecución. El temporizador está configurado para ejecutarse en los modos especificados por el parámetro de modos. Cuando el temporizador se dispara, el hilo intenta quitar la cola del mensaje del ciclo de ejecución y realizar el selector. Tiene éxito si el ciclo de ejecución se está ejecutando y en uno de los modos especificados; de lo contrario, el temporizador espera hasta que el ciclo de ejecución esté en uno de esos modos.

65

Como Jacob señala, aunque puedan parecer lo mismo, son cosas diferentes. De hecho, hay una diferencia significativa en la forma en que manejan el envío de acciones al hilo principal si ya se está ejecutando en el hilo principal.

Me encontré con esto recientemente, donde tenía un método común que a veces se ejecutaba desde algo en el hilo principal, a veces no. Para proteger ciertas actualizaciones de UI, he estado usando -performSelectorOnMainThread: para ellos sin problemas.

Cuando cambié a usar dispatch_sync en la cola principal, la aplicación se bloquea cuando este método se ejecuta en la cola principal. La lectura de la documentación sobre dispatch_sync, vemos:

llama a esta función y la orientación los resultados de cola actual en punto muerto.

donde por -performSelectorOnMainThread: vemos

esperar

booleano que especifica si los secuencias de rosca actual hasta después de que el selector especificado se lleva a cabo en el receptor en el hilo principal . Especifique SÍ para bloquear este hilo; de lo contrario, especifique NO para que este método devuelva inmediatamente.

Si el hilo actual es también el principal hilo, y se especifica SI para este parámetro , el mensaje se entrega y se procesa inmediatamente.

todavía prefiero la elegancia de GCD, comprobando el mejor tiempo de compilación que proporciona, y su mayor flexibilidad en cuanto a los argumentos, etc., por lo que hizo esta pequeña función auxiliar para evitar los puntos muertos:

void runOnMainQueueWithoutDeadlocking(void (^block)(void)) 
{ 
    if ([NSThread isMainThread]) 
    { 
     block(); 
    } 
    else 
    { 
     dispatch_sync(dispatch_get_main_queue(), block); 
    } 
} 

Actualización: En respuesta a Dave Dribin señalando caveats section ondispatch_get_current_queue(), he cambiado a usar [NSThread isMainThread] en el código anterior.

Luego uso

runOnMainQueueWithoutDeadlocking(^{ 
    //Do stuff 
}); 

para realizar las acciones que necesita para asegurar el hilo principal, sin tener que preocuparse acerca de lo que pase el método original fue ejecutado el.

+1

@Joe - 'dispatch_sync()' al hilo principal aún podría causar un punto muerto en su aplicación si algo en el hilo principal estuviera bloqueado esperando un valor de su hilo de fondo (a través de 'dispatch_sync()' o algo más). Esto es muy poco probable, pero aún es posible. Es el problema estándar de enhebrado de dos hilos esperando que el otro haga algo, para que no se haga nada. –

+0

@Joe - Sí, si está ejecutando por completo en una cola no principal o un hilo, no necesita el código que tengo arriba. El problema del punto muerto que mencioné ahora también será un problema con este código. Eso es más un problema arquitectónico. En cuanto a los comentarios, vea esta pregunta de Meta: http://meta.stackexchange.com/questions/43019/how-do-comment-replies-work. –

+11

Desbordamiento de pedantería: puede usar 'dispatch_block_t' como el tipo de argumento en lugar del feo' void (^ block) (void) '. –

1

Se supone que la forma de GCD es más eficiente y fácil de manejar, y solo está disponible en iOS4 en adelante, mientras que el rendimiento se acepta en el iOS anterior y posterior.

Cuestiones relacionadas