¿Cómo despachar en la queue principal sincrónicamente sin un interlocking?

Necesito enviar un bloque en la queue principal sincrónicamente. No sé si actualmente estoy ejecutando el hilo principal o no. La solución ingenua se ve así:

dispatch_sync(dispatch_get_main_queue(), block); 

Pero si actualmente estoy dentro de un bloque que se ejecuta en la queue principal, esta llamada crea un punto muerto. (El envío síncrono espera que el bloque termine, pero el bloque ni siquiera comienza a ejecutarse, ya que estamos esperando que termine el actual).

El siguiente paso obvio es verificar la queue actual:

 if (dispatch_get_current_queue() == dispatch_get_main_queue()) { block(); } else { dispatch_sync(dispatch_get_main_queue(), block); } 

Esto funciona, pero es feo. Antes de, al less, esconderlo detrás de alguna function personalizada, ¿no hay una solución mejor para este problema? Insisto en que no puedo permitirme despachar el bloque de forma asíncrona: la aplicación se encuentra en una situación en la que el bloque distribuido de forma asíncrona se ejecutaría "demasiado tarde".

Necesito usar algo como esto regularmente en mis aplicaciones Mac y iOS, así que uso la siguiente function auxiliar (originalmente descrita en esta respuesta ):

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

a la que llamas por

 runOnMainQueueWithoutDeadlocking(^{ //Do stuff }); 

Esto es más o less el process que describes arriba, y he hablado con varios otros desarrolladores que han creado algo así de forma independiente para ellos mismos.

Utilicé [NSThread isMainThread] lugar de verificar dispatch_get_current_queue() , porque la sección de advertencias para esa function una vez advertía contra usar esto para las testings de identidad y la llamada estaba en desuso en iOS 6 .

Para sincronizar en la queue principal o en el hilo principal (que no es lo mismo) utilizo:

 import Foundation private let mainQueueKey = UnsafeMutablePointer<Void>.alloc(1) private let mainQueueValue = UnsafeMutablePointer<Void>.alloc(1) public func dispatch_sync_on_main_queue(block: () -> Void) { struct dispatchonce { static var token : dispatch_once_t = 0 } dispatch_once(&dispatchonce.token, { dispatch_queue_set_specific(dispatch_get_main_queue(), mainQueueKey, mainQueueValue, nil) }) if dispatch_get_specific(mainQueueKey) == mainQueueValue { block() } else { dispatch_sync(dispatch_get_main_queue(),block) } } extension NSThread { public class func runBlockOnMainThread(block: () -> Void ) { if NSThread.isMainThread() { block() } else { dispatch_sync(dispatch_get_main_queue(),block) } } public class func runBlockOnMainQueue(block: () -> Void) { dispatch_sync_on_main_queue(block) } } 

Recientemente comencé a experimentar un punto muerto durante las actualizaciones de la interfaz de usuario. Eso me llevó a esta pregunta de Stack Overflow, lo que me llevó a implementar una function de ayuda runOnMainQueueWithoutDeadlocking -type basada en la respuesta aceptada.

Sin embargo, el problema real es que cuando actualizaba la interfaz de usuario desde un bloque, había utilizado erróneamente dispatch_sync lugar de dispatch_async para get la queue Principal para las actualizaciones de la interfaz de usuario. Fácil de hacer con la finalización del código, y tal vez difícil de notar después del hecho.

Entonces, para otros que lean esta pregunta: si no se requiere la ejecución síncrona , simplemente usar la dispatch_**a**sync evitará el interlocking que puede estar golpeando intermitentemente.