¿Cuál es la razón exacta para usar dispatch_once en el acceso de instancia compartida de un 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 instanciar el singleton asincrónicamente en segundo plano? Quiero decir, ¿qué sucede si solicito esa instancia compartida y confío en ella de inmediato, pero dispatch_once toma hasta Navidad para crear mi objeto? No vuelve de inmediato, ¿verdad? Al menos ese parece ser el objetivo de Grand Central Dispatch.
Entonces, ¿por qué están haciendo esto?
ios
objective-c
singleton
automatic-ref-counting
Miembro orgulloso
fuente
fuente
Note: static and global variables default to zero.
Respuestas:
dispatch_once()
Es absolutamente sincrónico. No todos los métodos GCD hacen las cosas de forma asíncrona (en este caso,dispatch_sync()
es síncrono). El uso dedispatch_once()
reemplaza el siguiente modismo: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 haciendo alloc init de su SharedInstance, si todos lo intentan al mismo tiempo exacto. No permitirá que se creen dos instancias. La ideadispatch_once()
es "realizar algo una vez y solo una vez", que es precisamente lo que estamos haciendo.fuente
dispatch_once()
es realmente simple (especialmente porque Xcode incluso lo completará automáticamente en un fragmento de código completo para usted) y significa que nunca tendrá que considerar si el método debe ser seguro para subprocesos.+initialize
antes de que se toque la clase, incluso si aún no está intentando crear su instancia compartida. En general, la inicialización diferida (crear algo solo cuando es necesario) es mejor. En segundo lugar, incluso su reclamo de rendimiento no es cierto.dispatch_once()
tiene casi exactamente la misma cantidad de tiempo como decirif (self == [MyClass class])
en+initialize
. Si ya tiene un+initialize
, entonces sí, crear la instancia compartida allí es más rápido, pero la mayoría de las clases no.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 GCD se ejecutan de forma asincrónica.
fuente