Реализация шаблона Singleton
Я видел эту конкретную реализацию шаблона Singleton везде:
+ (CargoBay *)sharedManager {
static CargoBay *_sharedManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_sharedManager = [[CargoBay alloc] init];
});
return _sharedManager;
}
и это, кажется, считается хорошей практикой (в частности, это из CargoBay).
Единственная часть, которую я не понимаю, это первая строка static CargoBay *_sharedManager = nil;
,
Почему вы устанавливаете это static
переменная к nil
?
2 ответа
Это просто вопрос читабельности, условности и практики. Это на самом деле не нужно, потому что:
Один. Его значение никогда не будет проверено. В более старых реализациях синглтона были известные
+ (id)sharedInstance
{
static SomeClass *shared = nil;
if (shared == nil)
shared = [[SomeClass alloc] init];
return shared;
}
код - чтобы этот метод работал, переменная поддержки должна быть инициализирована равной nil, так как, если бы она не была nil в первый раз, она ложно пропустила alloc-init в части if и возвратила бы указатель мусора. Однако с решением GCD ноль-проверка больше не нужна - GCD обрабатывает прагму "выполнить этот код только один раз".
Два. Но тем не менее: статические переменные неявно инициализируются нулями. Так что даже если вы просто напишите static id shared;
это будет изначально nil
,
Три. Почему это может быть хорошей практикой? Потому что, несмотря на первые две причины, о которых я упомянул, читателю исходного кода все же удобнее читать, что что-то явно инициализируется нулем. Или могут даже существовать некоторые несоответствующие реализации, где статические переменные не инициализируются должным образом автоматически, и тогда это действие должно быть предпринято.
Вы устанавливаете это в ноль, чтобы гарантировать, что вы получаете чистый экземпляр.
Это более читаемая версия того, что вы хотите сделать:
+ (GlobalVariables *)sharedInstance {
// the instance of this class is stored here
static GlobalVariables *myInstance = nil;
// check to see if an instance already exists
if (nil == myInstance) {
myInstance = [[[self class] alloc] init];
}
// return the instance of this class
return myInstance;
}
Но есть множество постов, показывающих, как это потенциально не может быть потокобезопасным, поэтому переходя к гибридному методу, описанному выше, и тому, что я опубликовал, вы получите следующее:
// Declared outside Singleton Manager
static SingletonClass *myInstance = nil;
+ (GlobalVariables *)sharedInstance {
if (nil != myInstance) {
return myInstance;
}
static dispatch_once_t pred; // Lock
dispatch_once(&pred, ^{ // This code is called at most once per app
myInstance = [[GlobalVariables alloc] init];
});
return myInstance;
}