Редагувати: Ця реалізація застаріла з 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
.
Ви можете подумати, що вам слід неявно перевірити наявність ініціалізації дублікатів у вашому блоці init:
- (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.)