Edit: This implementation obsoleted with ARC. Please have a look at How do I implement an Objective-C singleton that is compatible with ARC? for correct implementation.
All the implementations of initialize I've read in other answers share a common error.
+ (void) initialize {
_instance = [[MySingletonClass alloc] init] // <----- Wrong!
}
+ (void) initialize {
if (self == [MySingletonClass class]){ // <----- Correct!
_instance = [[MySingletonClass alloc] init]
}
}
The Apple documentation recommend you check the class type in your initialize block. Because subclasses call the initialize by default. There exists a non-obvious case where subclasses may be created indirectly through KVO. For if you add the following line in another class:
[[MySingletonClass getInstance] addObserver:self forKeyPath:@"foo" options:0 context:nil]
Objective-C will implicitly create a subclass of MySingletonClass resulting in a second triggering of +initialize
.
You may think that you should implicitly check for duplicate initialization in your init block as such:
- (id) init { <----- Wrong!
if (_instance != nil) {
// Some hack
}
else {
// Do stuff
}
return self;
}
But you will shoot yourself in the foot; or worse give another developer the opportunity to shoot themselves in the foot.
- (id) init { <----- Correct!
NSAssert(_instance == nil, @"Duplication initialization of singleton");
self = [super init];
if (self){
// Do stuff
}
return self;
}
TL;DR, here's my implementation
@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
(Replace ZAssert with our own assertion macro; or just NSAssert.)