Modifica: questa implementazione è obsoleta con ARC. Dai un'occhiata a Come posso implementare un singleton Objective-C compatibile con ARC? per una corretta implementazione.
Tutte le implementazioni di inizializzazione che ho letto in altre risposte condividono un errore comune.
+ (void) initialize {
_instance = [[MySingletonClass alloc] init] // <----- Wrong!
}
+ (void) initialize {
if (self == [MySingletonClass class]){ // <----- Correct!
_instance = [[MySingletonClass alloc] init]
}
}
La documentazione Apple consiglia di verificare il tipo di classe nel blocco di inizializzazione. Perché le sottoclassi chiamano l'inizializzazione per impostazione predefinita. Esiste un caso non ovvio in cui le sottoclassi possono essere create indirettamente tramite KVO. Perché se aggiungi la seguente riga in un'altra classe:
[[MySingletonClass getInstance] addObserver:self forKeyPath:@"foo" options:0 context:nil]
Objective-C creerà implicitamente una sottoclasse di MySingletonClass con conseguente seconda attivazione di +initialize
.
Potresti pensare che dovresti controllare implicitamente l'inizializzazione duplicata nel tuo blocco init in quanto tale:
- (id) init { <----- Wrong!
if (_instance != nil) {
// Some hack
}
else {
// Do stuff
}
return self;
}
Ma ti sparerai al piede; o peggio, dare a un altro sviluppatore l'opportunità di spararsi al piede.
- (id) init { <----- Correct!
NSAssert(_instance == nil, @"Duplication initialization of singleton");
self = [super init];
if (self){
// Do stuff
}
return self;
}
TL; DR, ecco la mia implementazione
@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
(Sostituisci ZAssert con la nostra macro di asserzioni; o solo NSAssert.)