Если вы можете ориентироваться на iOS 4.0 или выше
Используя GCD, это лучший способ создать синглтон в Objective-C (потокобезопасный)?
+ (instancetype)sharedInstance
{
static dispatch_once_t once;
static id sharedInstance;
dispatch_once(&once, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
instancetype
. Завершение кода намного лучше при использовании этого вместоid
.Ответы:
Это совершенно приемлемый и потокобезопасный способ создания экземпляра вашего класса. Технически это не может быть «синглтон» (в этом случае может быть только один из этих объектов), но если вы используете
[Foo sharedFoo]
метод только для доступа к объекту, этого достаточно.источник
instancetype
instancetype
это только одно из многих расширений языкаObjective-C
, с каждым новым выпуском добавляются новые.Знай это, люби это.
И возьмем это как пример того, как внимание к деталям низкого уровня может дать вам представление о новых мощных способах преобразования Objective-C.
Обратитесь сюда: instancetype
источник
MySingleton.h
MySingleton.m
источник
init
?MySingleton
, например,MySingleton.m
я звоню[super alloc]
Вы можете избежать выделения класса с помощью перезаписи метода alloc.
источник
Дэйв прав, это прекрасно. Возможно, вы захотите проверить документы Apple по созданию синглтона, чтобы получить советы по реализации некоторых других методов, чтобы гарантировать, что только один из них может быть создан, если классы решат НЕ использовать метод sharedFoo.
источник
Если вы хотите убедиться, что [[MyClass alloc] init] возвращает тот же объект, что и sharedInstance (на мой взгляд, это необязательно, но некоторые люди этого хотят), это можно сделать очень легко и безопасно с помощью второго dispatch_once:
Это позволяет любой комбинации [[MyClass alloc] init] и [MyClass sharedInstance] возвращать один и тот же объект; [MyClass sharedInstance] будет чуть более эффективным. Как это работает: [MyClass sharedInstance] вызовет [[MyClass alloc] init] один раз. Другой код может вызывать его также любое количество раз. Первый вызывающий для init выполнит «нормальную» инициализацию и сохранит одноэлементный объект в методе init. Любые последующие вызовы init будут полностью игнорировать возвращаемое alloc и возвращать тот же sharedInstance; результат alloc будет освобожден.
Метод + sharedInstance будет работать как обычно. Если это не первый вызывающий, который вызвал [[MyClass alloc] init], то результат init не является результатом вызова alloc, но это нормально.
источник
Вы спрашиваете, является ли это «лучшим способом создания синглтона».
Несколько мыслей:
Во-первых, да, это поточно-ориентированное решение. Этот
dispatch_once
шаблон - современный, потокобезопасный способ генерации синглетонов в Objective-C. Не беспокойтесь там.Вы спросили, однако, является ли это «лучшим» способом сделать это. Однако следует признать, что
instancetype
и[[self alloc] init]
может вводить в заблуждение при использовании в сочетании с синглетонами.Преимущество
instancetype
заключается в том, что это однозначный способ объявить, что класс можно разделить на подклассы, не прибегая к типуid
, как мы делали в прошлом году.Но
static
в этом методе возникают проблемы с подклассами. Что если быImageCache
иBlobCache
синглтоны были подклассамиCache
суперкласса без реализации собственногоsharedCache
метода?Чтобы это работало, вы должны убедиться, что подклассы реализуют свой собственный
sharedInstance
(или как вы его называете для вашего конкретного класса) метод.В итоге ваш оригинал
sharedInstance
выглядит так, как будто он будет поддерживать подклассы, но это не так. Если вы намереваетесь поддерживать подклассы, по крайней мере, включите документацию, которая предупреждает будущих разработчиков, что они должны переопределить этот метод.Для лучшей совместимости со Swift вы, вероятно, захотите определить это как свойство, а не метод класса, например:
Затем вы можете написать геттер для этого свойства (реализация будет использовать предложенный
dispatch_once
вами шаблон):Преимущество этого состоит в том, что если пользователь Swift использует его, он делает что-то вроде:
Обратите внимание, что нет
()
, потому что мы реализовали это как свойство. Начиная с Swift 3, это, как правило, доступ к синглетам. Поэтому определение его как свойства помогает облегчить эту совместимость.Кроме того, если вы посмотрите на то, как Apple определяет свои синглтоны, это шаблон, который они приняли, например, их
NSURLSession
синглтон определяется следующим образом:Другим, очень незначительным соображением совместимости Swift было название синглтона. Лучше, если вы можете включить название типа, а не
sharedInstance
. Например, если класс былFoo
, вы можете определить свойство singleton какsharedFoo
. Или, если класс былDatabaseManager
, вы можете позвонить в собственностьsharedManager
. Тогда пользователи Swift могли сделать:Очевидно, что если вы действительно хотите использовать
sharedInstance
, вы всегда можете объявить имя Swift, если хотите:Ясно, что при написании кода Objective C мы не должны допускать, чтобы функциональность Swift перевешивала другие соображения дизайна, но, тем не менее, если мы можем написать код, который изящно поддерживает оба языка, это предпочтительнее.
Я согласен с другими, которые отмечают, что если вы хотите, чтобы это был настоящий синглтон, в котором разработчики не могут / не должны (случайно) создавать экземпляры своих собственных экземпляров,
unavailable
квалификатор включенinit
иnew
разумен.источник
Чтобы создать потокобезопасный синглтон, вы можете сделать так:
и этот блог очень хорошо объясняет синглтоны в objc / cocoa
источник
источник
источник