Изменить: эта реализация устарела с ARC. Пожалуйста, ознакомьтесь с разделом Как реализовать синглтон Objective-C, совместимый с ARC? для правильной реализации.
Все реализации инициализации, которые я читал в других ответах, имеют общую ошибку.
+ (void) initialize {
_instance = [[MySingletonClass alloc] init] // <----- Wrong!
}
+ (void) initialize {
if (self == [MySingletonClass class]){ // <----- Correct!
_instance = [[MySingletonClass alloc] init]
}
}
В документации Apple рекомендуется проверить тип класса в блоке инициализации. Потому что подклассы вызывают инициализацию по умолчанию. Существует неочевидный случай, когда подклассы могут создаваться косвенно через KVO. Если вы добавите следующую строку в другой класс:
[[MySingletonClass getInstance] addObserver:self forKeyPath:@"foo" options:0 context:nil]
Objective-C неявно создаст подкласс MySingletonClass, что приведет ко второму срабатыванию +initialize
.
Вы можете подумать, что вам следует неявно проверять дубликат инициализации в вашем блоке инициализации следующим образом:
- (id) init { <----- Wrong!
if (_instance != nil) {
// Some hack
}
else {
// Do stuff
}
return self;
}
Но ты будешь стрелять себе в ногу; или еще хуже, дают другому разработчику возможность выстрелить себе в ногу.
- (id) init { <----- Correct!
NSAssert(_instance == nil, @"Duplication initialization of singleton");
self = [super init];
if (self){
// Do stuff
}
return self;
}
TL; DR, вот моя реализация
@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
(Замените ZAssert нашим собственным макросом утверждений; или просто NSAssert.)