Мой метод одноэлементного метода доступа обычно представляет собой вариант:
static MyClass *gInstance = NULL;
+ (MyClass *)instance
{
@synchronized(self)
{
if (gInstance == NULL)
gInstance = [[self alloc] init];
}
return(gInstance);
}
Что я мог сделать, чтобы улучшить это?
objective-c
design-patterns
singleton
object-initializers
нейтральный гласный звук
источник
источник
Ответы:
Другим вариантом является использование
+(void)initialize
метода. Из документации:Таким образом, вы можете сделать что-то похожее на это:
источник
+initialize
их суперклассовая реализация будет вызвана, если подкласс используется впервые.release
метод и сделать его пустым. :)[Источник]
источник
MySingleton *s = [[MySingelton alloc] init];
Pro Objective-C Design Patterns for iOS
и в ней объясняется, как вы делаете "строгий" Singelton. По сути, поскольку вы не можете сделать инициализирующие методы частными, вам необходимо переопределить методы alloc и copy. Поэтому, если вы попытаетесь сделать что-то подобное,[[MySingelton alloc] init]
вы получите ошибку во время выполнения (но, к сожалению, не во время компиляции). Я не понимаю, как все детали создания объекта, но вы реализуете,+ (id) allocWithZone:(NSZone *)zone
что называетсяsharedSingleton
На мой другой ответ ниже, я думаю, что вы должны делать:
источник
Поскольку Кендалл опубликовал поточный синглтон, который пытается избежать затрат на блокировку, я подумал, что я тоже добавлю:
Хорошо, позвольте мне объяснить, как это работает:
Быстрый случай: в нормальном исполнении
sharedInstance
уже был установлен, поэтомуwhile
цикл никогда не выполняется, и функция возвращается после простого тестирования на существование переменной;Медленный случай: если
sharedInstance
не существует, то экземпляр выделяется и копируется в него с помощью Compare And Swap ('CAS');Спорный случай: если две нити и попытка вызова
sharedInstance
в то же время ИsharedInstance
не существует в то же время , то они оба инициализации новых экземпляры одноточечного и попытаться CAS его в положение. Независимо от того, кто выиграл, CAS немедленно возвращается, а тот, который проиграл, освобождает только что выделенный экземпляр и возвращает (теперь установлено)sharedInstance
. СинглOSAtomicCompareAndSwapPtrBarrier
действует как барьер записи для потока настройки и барьер чтения из потока тестирования.источник
init
метод должен делать в вашем подходе?sharedInstance
Я полагаю, что генерировать исключение при инициализации не очень хорошая идея. Что делать, чтобы пользователь не звонилinit
напрямую много раз?источник
[[self alloc] init]
sharedInst.Изменить: эта реализация устарела с ARC. Пожалуйста, ознакомьтесь с разделом Как реализовать синглтон Objective-C, совместимый с ARC? для правильной реализации.
Все реализации инициализации, которые я читал в других ответах, имеют общую ошибку.
В документации Apple рекомендуется проверить тип класса в блоке инициализации. Потому что подклассы вызывают инициализацию по умолчанию. Существует неочевидный случай, когда подклассы могут создаваться косвенно через KVO. Если вы добавите следующую строку в другой класс:
Objective-C неявно создаст подкласс MySingletonClass, что приведет ко второму срабатыванию
+initialize
.Вы можете подумать, что вам следует неявно проверять дубликат инициализации в вашем блоке инициализации следующим образом:
Но ты будешь стрелять себе в ногу; или еще хуже, дают другому разработчику возможность выстрелить себе в ногу.
TL; DR, вот моя реализация
(Замените ZAssert нашим собственным макросом утверждений; или просто NSAssert.)
источник
Подробное объяснение макроса кода Singleton есть в блоге Cocoa With Love
http://cocoawithlove.com/2008/11/singletons-appdelegates-and-top-level.html .
источник
У меня есть интересная вариация на sharedInstance, которая является поточно-ориентированной, но не блокируется после инициализации. Я еще не уверен в этом, чтобы изменить верхний ответ в соответствии с запросом, но я представляю его для дальнейшего обсуждения:
источник
class_replaceMethod
чтобы превратитьсяsharedInstance
в клонаsimpleSharedInstance
. Таким образом, вам никогда не придется беспокоиться о получении@synchronized
блокировки снова.Краткий ответ: сказочный.
Длинный ответ: что-то вроде ....
Обязательно прочитайте заголовок dispatch / once.h, чтобы понять, что происходит. В этом случае комментарии заголовка более применимы, чем документы или справочная страница.
источник
Я свернул одноэлементный класс в класс, чтобы другие классы могли наследовать одноэлементные свойства.
Singleton.h:
Singleton.m:
И вот пример некоторого класса, который вы хотите стать синглтоном.
Единственное ограничение в отношении класса Singleton - это то, что это подкласс NSObject. Но чаще всего я использую синглтоны в своем коде, они на самом деле являются подклассами NSObject, поэтому этот класс действительно облегчает мою жизнь и делает код чище.
источник
@synchronized
он ужасно медленный и его следует избегать.Это работает и в среде без сбора мусора.
источник
Не должно ли это быть поточно-ориентированным и избежать дорогой блокировки после первого звонка?
источник
Вот макрос, который я собрал:
http://github.com/cjhanson/Objective-C-Optimized-Singleton
Это основано на работе здесь Мэтта Галлахера. Но изменив реализацию, чтобы использовать метод Swizzling, как описано здесь Дейвом МакЛахланом из Google .
Я приветствую комментарии / вклады.
источник
Как насчет
То есть вы избегаете затрат на синхронизацию после инициализации?
источник
Для подробного обсуждения шаблона синглтона в Objective-C, посмотрите здесь:
Использование шаблона Singleton в Objective-C
источник
KLSingleton
источник
NSLog(@"initialize: %@", NSStringFromClass([self class]));
в+initialize
метод, вы можете проверить, что классы инициализируются только один раз.Вы не хотите синхронизироваться с самим собой ... Так как сам объект еще не существует! Вы в конечном итоге блокируете временное значение идентификатора. Вы хотите, чтобы никто другой не мог запускать методы класса (sharedInstance, alloc, allocWithZone: и т. Д.), Поэтому вместо этого вам необходимо выполнить синхронизацию с объектом класса:
источник
self
объект не существует в методе класса. Среда выполнения определяет, какую реализацию метода вызывать, основываясь на том же значении, которое она предоставляетself
для каждого метода (класса или экземпляра).self
находится объект класса. Попробуйте сами:#import <Foundation/Foundation.h> @interface Eggbert : NSObject + (BOOL) selfIsClassObject; @end @implementation Eggbert + (BOOL) selfIsClassObject { return self == [Eggbert class]; } @end int main (int argc, const char * argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; NSLog(@"%@", [Eggbert selfIsClassObject] ? @"YES" : @"NO"); [pool drain]; return 0; }
Просто хотел оставить это здесь, чтобы я не потерял это. Преимущество этого в том, что его можно использовать в InterfaceBuilder, что является ОГРОМНЫМ преимуществом. Это взято из другого вопроса, который я задал :
источник
источник
Я знаю, что есть много комментариев к этому «вопросу», но я не вижу много людей, предлагающих использовать макрос для определения синглтона. Это такой общий шаблон, и макрос значительно упрощает синглтон.
Вот макросы, которые я написал на основе нескольких реализаций Objc, которые я видел.
Singeton.h
Пример использования:
MyManager.h
MyManager.m
Зачем макрос интерфейса, когда он почти пуст? Согласованность кода между заголовком и файлами кода; ремонтопригодность на случай, если вы захотите добавить больше автоматических методов или изменить их.
Я использую метод инициализации для создания синглтона, который используется в самом популярном ответе здесь (на момент написания).
источник
С помощью методов класса Objective C мы можем просто избежать использования шаблона синглтона обычным способом:
чтобы:
оборачивая класс в другой класс, который имеет только методы класса , таким образом, нет никакой возможности случайно создать дублирующиеся экземпляры, так как мы не создаем ни одного экземпляра!
Я написал более подробный блог здесь :)
источник
Чтобы расширить пример из @ robbie-hanson ...
источник
Мой способ прост, как это:
Если синглтон уже инициализирован, блок LOCK не будет введен. Вторая проверка (! Initialized) должна убедиться, что она еще не инициализирована, когда текущий поток получает LOCK.
источник
initialized
такvolatile
же достаточна. См. Aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf .Я не прочитал все решения, так что простите, если этот код является избыточным.
Это самая многопоточная реализация на мой взгляд.
источник
Я обычно использую код, примерно такой же, как в ответе Бена Хоффштейна (который я также получил из Википедии). Я использую его по причинам, изложенным Крисом Хансоном в его комментарии.
Однако иногда мне нужно поместить синглтон в NIB, и в этом случае я использую следующее:
Я оставляю реализацию
-retain
(и т. Д.) Читателю, хотя приведенный выше код - это все, что вам нужно в среде сборки мусора.источник
Принятый ответ, хотя и компилируется, неверен.
Согласно документации Apple:
... Вы можете использовать аналогичный подход для синхронизации методов класса связанного класса, используя объект Class вместо self.
Даже если использование self работает, это не должно, и это похоже на ошибку копирования и вставки для меня. Правильная реализация для метода фабрики классов:
источник
self
это объект класса внутри метода класса. Смотрите мой комментарий для фрагмента, демонстрирующего это.self
существует, но использование его в качестве переданного идентификатора@synchronized
синхронизирует доступ к методам экземпляра. Как указывает @ user490696, есть случаи (например, одиночные), когда использование объекта класса предпочтительнее. Из Руководства по программированию в Obj-C:You can take a similar approach to synchronize the class methods of the associated class, using the class object instead of self. In the latter case, of course, only one thread at a time is allowed to execute a class method because there is only one class object that is shared by all callers.