Das Singleton-Muster ist eine beliebte Technik zur Erstellung eines Objekts, das als einzige Instanz in der Anwendung existiert. In Swift wurde die Implementierung des Musters dank der Unterstützung für statische Eigenschaften und Thread-Sicherheit vereinfacht.
Historie der Frage:
In Objective-C erforderte die Implementierung von Singleton langen und komplizierten Code, der mit Thread-Sicherheit verbunden war. In Swift wurde dieses Problem durch lazy Initialisierung von statischen Eigenschaften gelöst.
Problem:
Singletons werden häufig für den zentralen Zugriff auf den Anwendungszustand (z. B. Session, Konfiguration, Dienste) verwendet, aber eine falsche Verwendung führt zu impliziten Abhängigkeiten und verringert die Testbarkeit des Codes.
Lösung:
In Swift wird das Muster durch eine statische Konstante des Typs implementiert. Dies gewährleistet Thread-Sicherheit und Eindeutigkeit:
Beispielcode:
final class Logger { static let shared = Logger() private init() {} func log(_ message: String) { print(message) } } Logger.shared.log("Beispiel für die Verwendung von Singleton")
Hauptmerkmale:
Kann und sollte man immer Singleton für alle Dienste der Anwendung verwenden?
Nein. Singletons sind für truly global state (z. B. ApplicationSettings) sinnvoll, aber es ist falsch, sie für Dienste der Geschäftslogik zu verwenden: Es entstehen enge Kopplungen und Probleme mit Unit-Tests.
Gewährleistet static let die thread-sichere Initialisierung von Singleton in Swift?
Ja, seit Swift 1.2 (und aufgrund der Runtime-Architektur) ist static let von Natur aus threadsicher — es wird einmal initiiert, selbst bei konkurrierenden Threads.
Kann Singleton vererbt werden?
Nein. Es ist besser, die Klasse als final zu deklarieren, um Vererbung zu vermeiden — andernfalls können zwei Instanzen von Singletons verschiedener abgeleiteter Klassen erstellt werden, was die Grundidee des Musters verletzt.
Ein Netzwerkdienst wird über Singleton implementiert, und die Methoden verwenden den globalen Zustand. In Unit-Tests entsteht eine implizite Abhängigkeit, der Dienst kann nicht wiederverwendet werden.
Vorteile:
Nachteile:
Singleton wird nur für truly-global Entitäten verwendet — z. B. ApplicationConfig. Alle Dienste erhalten Abhängigkeiten über einen expliziten Injector.
Vorteile:
Nachteile: