Можно ли установить singleton обратно в nil?
Я реализовал одноэлементный объект, используя обычный шаблон. Мой вопрос: возможно ли вернуть этот объект в нуль, так что на более поздней странице [MySingleton sharedInstance] объект будет повторно инициализирован?
// Get the shared instance and create it if necessary.
+ (MySingleton *)sharedInstance {
static dispatch_once_t pred;
static MySingleton *shared = nil;
dispatch_once(&pred, ^{
shared = [[MySingleton alloc] init];
});
return shared;
}
// We can still have a regular init method, that will get called the first time the Singleton is used.
- (id)init
{
self = [super init];
if (self) {
// Work your initialising magic here as you normally would
}
return self;
}
Я предполагаю, что
MySingleton *shared = [MySingleton sharedInstance];
shared = nil;
устанавливает только локальный указатель shared
в nil
. В конце концов, shared
объявляется как static
.
Ответы
Ответ 1
Ваше предположение о локальной ссылке правильное, это не повлияет на ваш синглтон.
Чтобы иметь возможность повторно инициализировать синглтон, вам нужно переместить статическую переменную из вашего метода, чтобы она была доступна для всего класса.
static MySingleton *sharedInstance = nil;
// Get the shared instance and create it if necessary.
+ (MySingleton *)sharedInstance {
if (sharedInstance == nil) {
sharedInstance = [[MySingleton alloc] init];
}
return sharedInstance;
}
+ (void)resetSharedInstance {
sharedInstance = nil;
}
Обратите внимание, что вы больше не можете использовать dispatch_once
, так как ваш singleton должен быть создан несколько раз. Если вы только когда-либо называете этот синглтон из своего пользовательского интерфейса (и, следовательно, только из основного потока), то пример выше в порядке.
Если вам нужен доступ из нескольких потоков, вам нужно поместить блокировку вокруг методов +sharedInstance
и +resetSharedInstance
, например.
+ (id)sharedInstance {
@synchronized(self) {
if (sharedInstance == nil) {
sharedInstance = [[MySingleton alloc] init];
}
return sharedInstance;
}
}
+ (void)resetSharedInstance {
@synchronized(self) {
sharedInstance = nil;
}
}
Это немного медленнее, чем вариант dispatch_once
, но на практике это не имеет значения.
Ответ 2
Да, но ваш метод singleton sharedInstance
определяет его как static
внутри этого метода, а ваш окончательный образец кода просто устанавливает локальную переменную (по совпадению, также называемую shared
) на nil
, оставляя static
внутри sharedInstance
без изменений. Таким образом, вы просто nil
, указав локальный указатель, не меняя static
внутри sharedInstance
.
Если вы хотите выполнить то, что вы просите, вам придется вытащить переменную static
, shared
, из метода sharedInstance
(и предположительно написать некоторый метод reset
для nil
Это). Ваш метод sharedInstance
также больше не может полагаться на dispatch_once
, но должен проверить, не является ли это static
nil
или нет.
Ответ 3
Я сделал это. Я не уверен, что это лучший способ, но, похоже, он работает нормально.
static dispatch_once_t pred;
static MySingleton *shared = nil;
+(MySingleton *)sharedInstance {
dispatch_once(&pred, ^{
shared = [[MySingleton alloc] init];
});
return shared;
}
+(void)clearSharedInstance {
shared = nil;
pred = nil;
}