Realizar en Next Run Loop: ¿Qué hay de malo con GCD?

Estoy probando estos dos enfoques:

dispatch_async(dispatch_get_main_queue(),^{ [self handleClickAsync]; }); 

y

 [self performSelector:@selector(handleClickAsync) withObject:nil afterDelay:0]; 

En respuesta a un button presionar.

El segundo permite que el UIButton resalte como uno esperaría y realice el handleClickAsync en el siguiente ciclo de ejecución (supongo: "algún time después" seguro). El primero no permite que la instancia de UIButton encienda hasta que la operación se haya completado por completo.

¿Cuál es la forma correcta de hacer esto con GCD o es performSelector la única manera?

Creo que la respuesta se encuentra aquí en una discusión sobre la queue de despacho principal :

Esta queue funciona con el ciclo de ejecución de la aplicación (si hay uno presente) para intercala la ejecución de tareas en queue con la ejecución de otras fonts de events conectadas al ciclo de ejecución.

En otras palabras, la queue de envío principal configura una queue secundaria (junto con la queue de events estándar proporcionada por UIApplicationMain() para el event handling bloques enviados a la queue principal. Cuando los bloques están presentes en la queue, el ciclo de ejecución alternará las tareas de UIApplicationMain() queue del queue de events principal y la queue de despacho. Por otro lado, la reference para el parámetro de delay de -performSelector:withObject:afterDelay: señala que:

Especificar un retraso de 0 no necesariamente hace que el selector se realice de inmediato. El selector todavía está en queue en el bucle de ejecución del hilo y se realizó tan pronto como sea posible.

Por lo tanto, cuando utiliza el selector de ejecución, la operación se pone en queue al final de la queue de events principal y no se realizará hasta que se haya procesado todo lo que esté delante de él en la queue (presumiblemente incluyendo el código para UIButton el UIButton ). Sin embargo, cuando usa la queue de despacho principal, agrega el bloque a la queue secundaria, que luego probablemente se procesa inmediatamente (es decir, en el siguiente ciclo de ejecución) suponiendo que no hay otros bloques en la queue principal. En este caso, el código para desbloquear el button todavía está en la queue del evento principal mientras que el ciclo de ejecución procesa el evento desde la queue del bloque secundario.

Creo que esto llegará a tu punto:

 [[NSOperationQueue mainQueue] addOperationWithBlock:^{ //bla bla bla }];