2013-03-17 2 views
12

Я читал много статей о потоках и блогах о том, как реализовать одноэлементный объектив-c, некоторые из них, возможно, немного устарели (год 2010 или ранее) и кажется, что у людей разные мнения по этому вопросу ... Имеет ли Apple документацию о внедрении синглета? Я не мог найти его. Если да, может кто-нибудь сказать мне, где?Objective-C singleton pattern in iOS 5+

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

@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]; 
} 

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

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

Благодаря

+0

Фактически ... это будет работать в iOS4? (Как любопытство.) – Fattie

+0

И может быть полезно, обратите внимание на исключительно простое представление кода в популярном ответе здесь: http://codereview.stackexchange.com/questions/19829/objective-c-singleton-implementation – Fattie

ответ

3

В Xcode, в разделе 'Поиск документации' введите Creating a Singleton Instance. Есть много результатов (но ссылка выше, внизу страницы, имеет пример кода).

+9

Не используйте код внизу этой страницы. Он предназначен исключительно для создания «строгого синглтона», как он отмечает. Они чрезвычайно редко встречаются в какао. Общие синглтоны являются нормой и не требуют большей части этого кода. Этот фрагмент кода вызвал много путаницы среди новых разработчиков Cocoa. Я рекомендую игнорировать его; вы вряд ли столкнетесь с случаями, когда это полезно. –

1

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

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

+0

Вы имеете в виду, что 'sharedObject' должен быть статической переменной? –

+0

О, конечно. Это была просто опечатка. Отредактировал его. – miho

12

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

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

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

Является ли использование синглетонов, действительно рекомендованных в iOS?

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

EDIT: у вас есть одна ошибка в коде. Вы должны позвонить [[self alloc] init], а не [[super alloc] init]. Нет причин когда-либо звонить +allocWithZone:, просто используйте +alloc. (Время, когда ...WithZone: методы полезны уже давно прошли.)

+0

Я не совсем понимаю это сам, но в книге BNR iOS они используют '[[super allocWithZone: nil] init]' и возвращают '[self sharedInstance]' в '+ allocWithZone:'. Приведенная здесь причина заключается в том, что 'alloc' просто вызывает' allocWithZone: ', что делает фактическое распределение. Использование '[super allocWithZone]' избегает кода, идущего в кругах, вызывая его собственный метод allocWithZone. –

+2

ах. Когда вы прекратите переопределять 'allocWithZone:' (который вы почти никогда не будете переопределять), это больше не будет проблемой. –

+0

Спасибо! И тогда, если переменные инициализируются путем переопределения метода 'init', как в« обычных »классах? – AppsDev

0

Немного предупреждения с помощью НОД для одиночек:

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

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

+ (void) initialize 

+1

Почему метод init получил доступ к экземпляру singleton? Я не могу представить случая, когда это произойдет. '+ initialize' не является более подходящим способом записи синглонов с момента выпуска GCD. (Это был хороший способ до этого.) –

+0

Здравствуйте, Роб :) Я хочу искренне поблагодарить вас за вашу замечательную книгу «Развитие iOS: Pushing the Limits», я узнал тонну от нее! Ну, это произошло в одном из моих приложений: метод init создавал экземпляр другого класса, а другой экземпляр обратился к объекту singleton до завершения dispatch_once (что вызывает тупик). Да, я знаю, что с точки зрения дизайна это не очень хорошо :) – cpprulez

+0

Точно.Здесь у вас проблема с дизайном, а не проблема с одноэлементным шаблоном. Вы, вероятно, слишком много делаете в init. Вы также можете использовать синглтон, который вам не нужен. Иногда люди слишком быстро переходят в одиночные игры, когда было бы лучше просто передать объект. –

0

Я до сих пор с помощью одноточечно заголовка штуковина из CocoaWithLove - может быть немного устаревшей, но все еще работает как очарование. Он в основном делает то же, что описано here, ссылаясь на документацию на яблоки, и я предполагаю, что документация Apple (bottom of this page) по-прежнему действительна. Есть люди, полагая, что он останется действительным на неопределенный срок. Это официальное решение, предложенное Apple.

+0

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