¿Por qué Apple recomienda utilizar Dispatch_once para implementar el patrón singleton en ARC?
¿Cuál es la razón exacta para usar despacho_once en el descriptor de acceso de instancia compartida de un singleton bajo 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 asincrónica en segundo plano? Quiero decir, ¿qué sucede si solicito esa instancia compartida y confío en ella de inmediato, pero despacho_once tarda hasta Navidad en crear mi objeto? No regresa inmediatamente ¿verdad? Al menos ese parece ser el objetivo de Grand Central Dispatch.
Entonces, ¿por qué están haciendo esto?
dispatch_once()
es absolutamente sincrónico. No todos los métodos de GCD hacen cosas de forma asincrónica (por ejemplo, dispatch_sync()
es sincrónico). El uso de dispatch_once()
reemplaza el siguiente modismo:
+ (MyClass *)sharedInstance {
static MyClass *sharedInstance = nil;
@synchronized(self) {
if (sharedInstance == nil) {
sharedInstance = [[MyClass alloc] init];
}
}
return sharedInstance;
}
El beneficio de dispatch_once()
esto es que es más rápido. También es semánticamente más limpio, porque también lo protege de múltiples subprocesos que realizan alloc init de su instancia compartida, si todos lo intentan al mismo tiempo. No permitirá que se creen dos instancias. La idea dispatch_once()
es "realizar algo una vez y sólo una vez", que es precisamente lo que estamos haciendo.
Porque sólo se ejecutará una vez. Entonces, si intentas 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 GCD se ejecutan de forma asincrónica.