ios - ¿Por qué Apple recomienda usar dispatch_once para implementar el patrón singleton bajo ARC?
objective-c automatic-ref-counting (2)
¿Cuál es la razón exacta para usar dispatch_once en el 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 asincrónicamente en segundo plano? Quiero decir, ¿qué sucede si solicito esa instancia compartida y confío en ella inmediatamente, pero dispatch_once tarda hasta la Navidad para crear mi objeto? No vuelve inmediatamente, ¿verdad? Al menos eso parece ser el punto central de Grand Central Dispatch.
Entonces, ¿por qué están haciendo esto?
Porque solo se ejecutará una vez. Así que si lo intentas y accedes dos veces desde hilos diferentes, no causará ningún problema.
Mike Ash tiene una descripción completa en su publicación del blog Care and Feeding of Singletons .
No todos los bloques GCD se ejecutan de forma asíncrona.
dispatch_once()
es absolutamente síncrono. No todos los métodos GCD hacen las cosas de forma asíncrona (por ejemplo, dispatch_sync()
es síncrono). El uso de dispatch_once()
reemplaza el siguiente idioma:
+ (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, ya que también lo protege de varios subprocesos que realizan el inicio de asignación de su instancia compartida, si todos intentan a la misma hora. 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.