Вы спрашиваете, является ли это "лучшим способом создания синглтона".
Во-первых, да, это потоковое решение,Этот шаблон dispatch_once
- это современный, потокобезопасный способ генерации синглетонов в Objective-C.Не беспокойтесь.
Вы спросили, однако, является ли это "лучшим" способом сделать это.Однако следует признать, что instancetype
и [[self alloc] init]
потенциально вводят в заблуждение при использовании в сочетании с синглетонами.
Преимущество instancetype
заключается в том, что это однозначный способ объявить, что класс можно разделить на подклассы, не прибегая к типу id
, как мы это делали в прошлом году.
Но static
в этом методе создает проблемы для подклассов.Что если бы синглеты ImageCache
и BlobCache
были подклассами суперкласса Cache
без реализации собственного метода sharedCache
?
ImageCache *imageCache = [ImageCache sharedCache]; // fine
BlobCache *blobCache = [BlobCache sharedCache]; // error; this will return the aforementioned ImageCache!!!
Чтобы это работало, вам нужно убедиться, что подклассыреализовать свой собственный метод sharedInstance
(или как вы его называете для вашего конкретного класса).
Итог, ваш оригинальный sharedInstance
выглядит как будто он будет поддерживать подклассы, но он выиграл 'т.Если вы намереваетесь поддерживать подклассы, по крайней мере, включите документацию, которая предупреждает будущих разработчиков, что они должны переопределить этот метод.
Для лучшей совместимости со Swift вы, вероятно, захотите определить, что этосвойство, а не метод класса, например:
@interface Foo : NSObject
@property (class, readonly, strong) Foo *sharedFoo;
@end
Затем вы можете написать геттер для этого свойства (реализация будет использовать предложенный вами шаблон dispatch_once
):
+ (Foo *)sharedFoo { ... }
Преимущество этого состоит в том, что если пользователь Swift использует его, он будет делать что-то вроде:
let foo = Foo.shared
Обратите внимание, что ()
нет, потому что мы реализовали его какимущество.Начиная с Swift 3, это, как правило, доступ к синглетам.Поэтому определение его как свойства помогает упростить эту совместимость.
В качестве отступления, если вы посмотрите на то, как Apple определяет их синглтоны, это шаблон, который они приняли, например, определен их NSURLSession
singleton.следующим образом:
@property (class, readonly, strong) NSURLSession *sharedSession;
Другим, очень незначительным соображением совместимости Swift было название синглтона.Лучше, если вы включите имя типа, а не sharedInstance
.Например, если класс был Foo
, вы можете определить свойство singleton как sharedFoo
.Или, если класс был DatabaseManager
, вы можете назвать свойство sharedManager
.Тогда пользователи Swift могут сделать:
let foo = Foo.shared
let manager = DatabaseManager.shared
Очевидно, что если вы действительно хотите использовать sharedInstance
, вы всегда можете объявить имя Swift, если хотите:
@property (class, readonly, strong) Foo* sharedInstance NS_SWIFT_NAME(shared);
Очевидно,при написании кода Objective-C мы не должны допускать, чтобы функциональность Swift перевешивала другие соображения дизайна, но все же, если мы можем написать код, который изящно поддерживает оба языка, это предпочтительнее.
Я согласенс другими, которые отмечают, что если вы хотите, чтобы это был настоящий синглтон, в котором разработчики не могут / не должны (случайно) создавать экземпляры своих собственных экземпляров, квалификатор unavailable
для init
и new
является разумным.