Edit: Эта реализация с ARC устарел. Пожалуйста, посмотрите на How do I implement an Objective-C singleton that is compatible with 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)
Что у вас есть хорошо, хотя вы могли бы переместить глобальную переменную декларацию в ваш + метод экземпляра (единственное место, где она должна быть использованы, если вы не позволяете ему быть установлены, а) и использовать имя типа + defaultMyClass или + sharedMyClass для вашего метода. + экземпляр не предназначен для выявления. – 2008-09-28 09:37:58