Вопрос по initialization, ios, objective-c, private-members, singleton – Синглтон-паттерн Objective-C в iOS 5+

12

Я читал много тем и статей в блогах о том, как реализовать синглтон в target-c, некоторые из них, возможно, немного устарели (2010 год или более ранняя версия), и кажется, что у людей разные мнения по этому вопросу. .. Есть ли у Apple документация по реализации синглтона? Я не мог найти это. Если так, может кто-нибудь сказать мне, где?

Мне нужен синглтон для класса, который имеет как публичные, так и приватные переменные. В настоящее время это реализация, которую я имею для такого класса:

@interface MySingleton ()
   @property (strong, nonatomic) NSString *state;
@end

@implementation MySingleton

@synthesize state = _state;
@synthesize count = _count;

static MySingleton *sharedObject = nil;

+ (MySingleton *)sharedInstance
{
   static dispatch_once_t _singletonPredicate;

   dispatch_once(&_singletonPredicate, ^{
      sharedObject = [[super allocWithZone:nil] init];
   });

   return sharedObject;
}

+ (id)allocWithZone:(NSZone *)zone 
{
   return [self sharedInstance];
}

Должен ли это быть рекомендуемый способ? И как я должен инициализировать переменные экземпляра, public и private?

Еще одна проблема, которую я хотел бы прояснить в отношении синглтона: это вызовет утечку памяти? Рекомендуется ли использование синглетонов в iOS?

Спасибо

И может быть полезным, обратите внимание на исключительно простое представление кода в популярном ответе здесь:codereview.stackexchange.com/questions/19829/... Fattie
На самом деле ... это будет работать в iOS4? (Из любопытства.) Fattie

Ваш Ответ

5   ответов
3

Создание экземпляра Singleton, Результатов много (но ссылка выше, внизу страницы, содержит пример кода).

Не используйте код внизу этой страницы слегка. Это исключительно для создания "строгого синглтона", как отмечается. Они чрезвычайно редки в какао. Общие синглтоны являются нормой и не требуют большей части этого кода. Этот фрагмент кода вызвал много путаницы среди новых разработчиков Какао. Я рекомендую игнорировать это; Вы вряд ли встретите случаи, когда это полезно. Rob Napier
0

CocoaWithLove - может быть немного устаревшим, но все еще работает как шарм. Это в основном делает то же самое, как описаноВот ссылаясь на документацию Apple, и я бы предположил, по крайней мере, документация Apple (нижняя часть этой страницы) все еще действует. Есть люди, предполагающие, что это будет оставаться в силе бесконечно, так как это официальное решение, предложенное Apple.

Привет, да, это все еще действует, однако это не эффективно, так как при каждом обращении к синглтону есть блокировка, даже если только один поток пытается получить к нему доступ. dispatch_once решает эту проблему. cpprulez
1

это рекомендуемый способ. Есть только одно небольшое различие в том, как я его использую: я определяюsharedObject в качестве статической переменной внутри+ (MySingleton *)sharedInstance метод, потому что не должно быть возможности получить доступ к переменной из другого места, чем из метода getter.

И нет, вы не создадите утечку памяти. Когда ваше приложение завершается, вся зарезервированная память, используемая вашим приложением, все равно будет освобождена, и не будет никакой другой ситуации, когда статический общий экземпляр должен быть освобожден. В области до ARC даже было обычнымrelease Метод действительно предотвращает случайное освобождение объекта.

Ты имеешь в видуsharedObject должна быть статическая переменная? Mike D
О Конечно. Была просто опечатка. Отредактировал это. miho
0

dispatch_once(&_singletonPredicate, ^{
      sharedObject = [[super allocWithZone:nil] init];
   });

если метод init по какой-либо причине обращается к одноэлементному объекту прямо или косвенно, возникает тупик. По этой причине я считаю, что более подходящим способом написания синглтона является

+ (void) initialize

метод

Привет, Роб :) Я хочу искренне поблагодарить тебя за твою замечательную книгу «Разработка для iOS: раздвигая границы», я многому из нее научился! Что ж, это произошло в одном из моих приложений: метод init создал экземпляр другого класса, и этот другой экземпляр обратился к одноэлементному объекту до завершения dispatch_once (что вызывает взаимоблокировку). Да, я знаю, что с точки зрения дизайна это не очень хорошо :) cpprulez
Почему метод init обращается к экземпляру синглтона? Я не могу представить себе случай, когда это произойдет.+initialize не является более подходящим способом написания синглетонов, так как GCD был выпущен. (Это был хороший способ до этого.) Rob Napier
Именно так. Здесь у вас проблема с дизайном, а не проблема с единичным шаблоном. Вы, вероятно, делаете слишком много в init. Вы также можете использовать синглтон, который вам не нужен. Иногда люди прыгают к синглетонам слишком быстро, когда лучше просто передать объект. Rob Napier
12

наряду с комментарием @ miho о включении статического объекта в метод sharedInstance. Но нет причин для переопределения+allocWithZone:, Синглтоны в ObjC, как правило, «общие», а не принудительные. Вы можете создавать другие экземпляры "синглтона". Если создавать другие экземпляры незаконно, вам следует сделатьinit выполнитьNSAssert вместо того, чтобы обмануть звонящего в+allocWithZone:, Если ваш синглтон изменчив (и большинство из них), вам абсолютно не следует переопределять+allocWithZone: сюда.

Еще одна проблема, которую я хотел бы прояснить в отношении синглтона: это вызовет утечку памяти?

Нет. Этот объект никогда не будет выпущен, но он всегда будет доступен. Это не утечка.

Рекомендуется ли использование синглетонов в iOS?

Да, и это очень распространенный шаблон, используемый во всех средах Какао. Тем не менее, существуют различные другие шаблоны, которые в последнее время стали несколько популярными среди разработчиков. Внедрение зависимостей вызывает некоторый интерес, хотя на практике я не вижу этого часто. Уменьшение вашей зависимости от синглетонов может улучшить тестируемость, и я недавно экспериментировал с тем, как с некоторым успехом устранить некоторые из них в моем коде. Но у них долгая гордая история в Какао, и я не считаю их проблемой.

РЕДАКТИРОВАТЬ: у вас есть одна фактическая ошибка в вашем коде. Вы должны звонить[[self alloc] init]не[[super alloc] init], Нет причин звонить+allocWithZone:, просто используйте+alloc, (Время, когда...WithZone: методы были полезны давно прошли.)

Ага. В синглетах нет ничего особенного, кроме того, что есть метод класса для получения «известного экземпляра». Кроме того, это просто нормальный класс. Rob Napier
Спасибо! И затем, если переменные инициализируются переопределениемinit метод, как в "обычных" классах? AppsDev
Я не совсем понимаю это, но в книге BNR iOS они используют[[super allocWithZone:nil] init] и вернуться[self sharedInstance] в+allocWithZone:, Причина в том, чтоalloc просто звонкиallocWithZone: который делает фактическое распределение. С помощью[super allocWithZone] избегает кода, идущего по кругу, вызывая свой собственныйallocWithZone метод. nevan king
ах. Когда вы перестанете переопределятьallocWithZone: (который вы почти никогда не должны отменять), это больше не будет проблемой. Rob Napier
Привет, @RobNapier, я опоздал, но я слышал из виноградной лозы, что могут быть редкие случаи, когда синглтон может быть инициирован более одного раза, его сложно проверить и т. Д. Я делал DI раньше в Java, но эта тема все еще неясна для меня относительно DI в Obj-C. Я надеялся, что вы могли бы так любезно связать мне пару чтений, касающихся DI в Obj-C, насколько сложно проверить синглтон, редкие случаи, когда синглтон инициируется более одного раза? Если бы вы сами написали блог обо всем этом, этого было бы достаточно. Гуглил, но большая часть результата о том, что я здесь упомянул, имеет отношение к Java. TY. Unheilig

Похожие вопросы