まず、はい、これはスレッドセーフなソリューションです。この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シングルトンは次のように定義されています。
@property (class, readonly, strong) NSURLSession *sharedSession;
もう1つの非常にマイナーなSwiftの相互運用性に関する考慮事項は、シングルトンの名前でした。タイプではなくタイプの名前を組み込むことができるのが最善ですsharedInstance。たとえば、クラスがの場合Foo、シングルトンプロパティをとして定義できます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あり、賢明であると指摘する他の人にも同意します。