Editar: Esta implementación está obsoleta con ARC. Por favor, eche un vistazo a ¿Cómo implemento un singleton Objective-C que sea compatible con ARC? Para una correcta implementación.
Todas las implementaciones de initialize que he leído en otras respuestas comparten un error común.
+ (void) initialize {
_instance = [[MySingletonClass alloc] init] // <----- Wrong!
}
+ (void) initialize {
if (self == [MySingletonClass class]){ // <----- Correct!
_instance = [[MySingletonClass alloc] init]
}
}
La documentación de Apple recomienda que verifique el tipo de clase en su bloque de inicialización. Porque las subclases llaman a initialize por defecto. Existe un caso no obvio en el que se pueden crear subclases indirectamente a través de KVO. Porque si agrega la siguiente línea en otra clase:
[[MySingletonClass getInstance] addObserver:self forKeyPath:@"foo" options:0 context:nil]
Objective-C creará implícitamente una subclase de MySingletonClass dando como resultado una segunda activación de +initialize
.
Puede pensar que debe verificar implícitamente la inicialización duplicada en su bloque de inicio como tal:
- (id) init { <----- Wrong!
if (_instance != nil) {
// Some hack
}
else {
// Do stuff
}
return self;
}
Pero te dispararás en el pie; o peor, dar a otro desarrollador la oportunidad de pegarse un tiro en el pie.
- (id) init { <----- Correct!
NSAssert(_instance == nil, @"Duplication initialization of singleton");
self = [super init];
if (self){
// Do stuff
}
return self;
}
TL; DR, aquí está mi implementación
@implementation MySingletonClass
static MySingletonClass * _instance;
+ (void) initialize {
if (self == [MySingletonClass class]){
_instance = [[MySingletonClass alloc] init];
}
}
- (id) init {
ZAssert (_instance == nil, @"Duplication initialization of singleton");
self = [super init];
if (self) {
// Initialization
}
return self;
}
+ (id) getInstance {
return _instance;
}
@end
(Reemplace ZAssert con nuestra propia macro de aserción; o simplemente NSAssert).