Objective-C singleton pattern в iOS 5+

Я читал много потоков и статей в блогах о том, как реализовать singleton в objective-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];
}

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

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

Спасибо

Ответ 1

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

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

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

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

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

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

Ответ 2

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

Ответ 3

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

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

Ответ 4

Немного предупреждения с использованием gcd для одиночных чисел:

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

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

+ (void) initialize

Метод

Ответ 5

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