Sie fragen, ob dies der "beste Weg ist, um Singleton zu erstellen".
Erstens, ja, dies ist eine thread-sichere Lösung. Dieses dispatch_once
Muster ist die moderne, thread-sichere Methode zum Generieren von Singletons in Objective-C. Keine Sorge da.
Sie haben jedoch gefragt, ob dies der "beste" Weg ist, dies zu tun. Man sollte jedoch anerkennen, dass das instancetype
und[[self alloc] init]
in Verbindung mit Singletons möglicherweise irreführend ist.
Der Vorteil von instancetype
ist, dass es eine eindeutige Methode ist, zu erklären, dass die Klasse in Unterklassen unterteilt werden kann, ohne auf eine Art von Klasse zurückzugreifenid
, wie wir es früher getan haben.
Aber das static
in dieser Methode stellt Unterklassenherausforderungen. Was wäre, wenn ImageCache
und BlobCache
Singletons beide Unterklassen einer Cache
Oberklasse wären, ohne ihre eigene sharedCache
Methode zu implementieren ?
ImageCache *imageCache = [ImageCache sharedCache]; // fine
BlobCache *blobCache = [BlobCache sharedCache]; // error; this will return the aforementioned ImageCache!!!
Damit dies funktioniert, müssen Sie sicherstellen, dass Unterklassen ihre eigenen implementieren sharedInstance
Methode (oder wie auch immer Sie sie für Ihre bestimmte Klasse nennen) .
Unterm Strich sharedInstance
sieht Ihr Original so aus, als würde es Unterklassen unterstützen, aber nicht. Wenn Sie Unterklassen unterstützen möchten, fügen Sie zumindest eine Dokumentation hinzu, die zukünftige Entwickler warnt, dass sie diese Methode überschreiben müssen.
Für eine optimale Interoperabilität mit Swift möchten Sie dies wahrscheinlich als eine Eigenschaft definieren, nicht als eine Klassenmethode, z. B.:
@interface Foo : NSObject
@property (class, readonly, strong) Foo *sharedFoo;
@end
Dann können Sie einen Getter für diese Eigenschaft schreiben (die Implementierung würde das von dispatch_once
Ihnen vorgeschlagene Muster verwenden):
+ (Foo *)sharedFoo { ... }
Dies hat den Vorteil, dass ein Swift-Benutzer, wenn er es verwendet, Folgendes tun würde:
let foo = Foo.shared
Beachten Sie, dass dies nicht der Fall ist ()
, da wir es als Eigenschaft implementiert haben. Ab Swift 3 wird im Allgemeinen auf Singletons zugegriffen. Die Definition als Eigenschaft erleichtert die Interoperabilität.
Abgesehen davon, wenn Sie sich ansehen, wie Apple ihre Singletons definiert, ist dies das Muster, das sie übernommen haben, z. B. ist ihr NSURLSession
Singleton wie folgt definiert:
@property (class, readonly, strong) NSURLSession *sharedSession;
Eine weitere, sehr geringfügige Überlegung zur Swift-Interoperabilität war der Name des Singletons. Es ist am besten, wenn Sie den Namen des Typs einfügen und nicht sharedInstance
. Wenn die Klasse beispielsweise war Foo
, können Sie die Singleton-Eigenschaft als definieren sharedFoo
. Oder wenn die Klasse war DatabaseManager
, können Sie die Eigenschaft aufrufen sharedManager
. Dann könnten Swift-Benutzer Folgendes tun:
let foo = Foo.shared
let manager = DatabaseManager.shared
Wenn Sie wirklich verwenden möchten sharedInstance
, können Sie den Swift-Namen jederzeit deklarieren , wenn Sie möchten:
@property (class, readonly, strong) Foo* sharedInstance NS_SWIFT_NAME(shared);
Wenn Sie Objective-C-Code schreiben, sollten wir nicht zulassen, dass die Swift-Interoperabilität andere Entwurfsüberlegungen überwiegt. Wenn wir jedoch Code schreiben können, der beide Sprachen ordnungsgemäß unterstützt, ist dies vorzuziehen.
Ich stimme anderen zu, die darauf hinweisen, dass, wenn Sie möchten, dass dies ein echter Singleton ist, bei dem Entwickler ihre eigenen Instanzen nicht (versehentlich) instanziieren können / sollten, das unavailable
Qualifikationsmerkmal aktiviert ist init
und new
umsichtig ist.