Правильный синглтон в Objective C
При чтении официальной документации посвященной iPhone OS, складывается впечатление что существуют всего 2 паттерна проектирования: Model View Controller и Delegate. В принципе, я согласен с таким подходом, описывать большое количество паттернов скорее вредно чем полезно, особенно для нового в какой-либо области человека. Тем не менее, я люблю пользоваться удобными и привычными подходами пусть даже и на новой платформе.
Загоревшись идеей заполучить в свое распоряжение паттерн Singleton, я немного погуглил и нашел на сайте stackoverflow.com достаточно интересную дискуссию на тему правильного синглтона для Objective C. С одной стороны, приводимые там реализации достаточно хороши, но не на столько, как хотелось бы. По большому счету, почти все «велосипедные» реализации этого паттерна на C++ имеют ту же проблему — отсутствие возможности провести деинициализацию объекта при завершении приложения. При том что Objective C имеет бесшовную состыковку с C, проблема решается достаточно просто. Можно зарегистрировать обработчик, который будет вызван при завершении работы приложения при помощи функции atexit(). Единственное что стоит не забывать при работе с функцией atexit, так это ограничение на возможное количество обработчиков — 32 штуки. За более детальной информацией можно обратиться в стандарт языка C, пункт 7.20.4.2 В результате должен получиться приблизительно следующий код:
// --- файл singleton.h --
@interface Singleton : NSObject {
}
+(Singleton*) instance;
@end
// -- файл singleton.m --
#import "Singleton.h";
@implementation Singleton
static Singleton *instance_;
static void singleton_remover() {
[instance_ release];
}
+ (Singleton*)instance {
@synchronized(self) {
if( instance_ == nil ) {
[[self alloc] init];
}
}
return instance_;
}
- (id)init {
self = [super init];
instance_ = self;
atexit(singleton_remover);
return self;
}
- (void)dealloc {
[super dealloc];
}
@end
К сожалению, в связи с отсутствием в Objective C такого понятия как шаблоны, код получается не универсальный и требует работы по принципу cut and paste, что не радует. Наверное, можно пойти по пути преобразования типов и изменить возвращаемый в instance тип на id. Но при детальном рассмотрении подобный подход мне нравится еще меньше.