2012-02-02 11 views
295

¿Cuál es el motivo exacto para usar dispatch_once en el acceso de instancia compartido de un singleton en ARC?¿Por qué Apple recomienda utilizar dispatch_once para implementar el patrón singleton en ARC?

+ (MyClass *)sharedInstance 
{ 
    // Static local predicate must be initialized to 0 
    static MyClass *sharedInstance = nil; 
    static dispatch_once_t onceToken = 0; 
    dispatch_once(&onceToken, ^{ 
     sharedInstance = [[MyClass alloc] init]; 
     // Do any other initialisation stuff here 
    }); 
    return sharedInstance; 
} 

¿No es una mala idea crear una instancia del singleton de forma asíncrona en el fondo? Me refiero a qué sucede si solicito esa instancia compartida y confío en ella inmediatamente, pero el dispatch_once tarda hasta Navidad para crear mi objeto. No regresa inmediatamente ¿verdad? Al menos ese parece ser el objetivo de Grand Central Dispatch.

¿Por qué están haciendo esto?

+0

'Nota: las variables estáticas y globales son predeterminadas a cero. – ikkentim

Respuesta

406

dispatch_once() es absolutamente sincrónico. No todos los métodos GCD hacen cosas de forma asíncrona (caso por ejemplo, dispatch_sync() es sincrónico). El uso de dispatch_once() sustituye a la siguiente lenguaje:

+ (MyClass *)sharedInstance { 
    static MyClass *sharedInstance; 
    @synchronized(self) { 
     if (sharedInstance == nil) { 
      sharedInstance = [[MyClass alloc] init]; 
     } 
    } 
    return sharedInstance; 
} 

El beneficio de dispatch_once() sobre esto es que es más rápido. También es semánticamente más limpio, porque también lo protege de múltiples hilos haciendo alloc init de su sharedInstance, si todos lo intentan en el mismo momento exacto. No permitirá que se creen dos instancias. La idea completa de dispatch_once() es "realizar algo una vez y solo una vez", que es precisamente lo que estamos haciendo.

+4

Por el bien del argumento, tengo que tener en cuenta que [documentación] (https://developer.apple.com/library/mac/documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html#//apple_ref/c/ func/dispatch_once) no dice que se está ejecutando sincrónicamente. Solo dice que múltiples invocaciones simultáneas serán serializadas. – expert

+5

Usted afirma que es más rápido, ¿cuánto más rápido? No tengo ninguna razón para pensar que no estás diciendo la verdad, pero me gustaría ver un punto de referencia simple. –

+29

Acabo de hacer un punto de referencia simple (en el iPhone 5) y parece que dispatch_once es aproximadamente 2 veces más rápido que @synchronized. –

39

Porque solo se ejecutará una vez. Por lo tanto, si intenta acceder a él dos veces desde diferentes hilos, no causará ningún problema.

Mike Ash tiene una descripción completa en su publicación de blog Care and Feeding of Singletons.

No todos los bloques de GCD se ejecutan de forma asíncrona.

+11

Kevin es una mejor respuesta, pero me voy a dejar la mía para mantener el enlace a la publicación de Mike Ash. – Abizern

Cuestiones relacionadas