Het singleton-patroon is een populaire techniek voor het creëren van een object dat in een unieke instantie in de applicatie bestaat. In Swift is de implementatie van het patroon vereenvoudigd door de ondersteuning van statische eigenschappen en threadveiligheid.
Achtergrond:
In Objective-C vereiste de implementatie van het Singleton langdurige en niet-triviale code met betrekking tot threadveiligheid. In Swift is dit probleem opgelost door middel van lazy initialization van statische eigenschappen.
Probleem:
Singletons worden vaak gebruikt voor gecentraliseerde toegang tot de staat van de applicatie (bijvoorbeeld Session, configuraties, services), maar verkeerd gebruik leidt tot impliciete afhankelijkheden en vermindert de testbaarheid van de code.
Oplossing:
In Swift wordt het patroon geïmplementeerd via een statische constante van het type. Dit garandeert threadveiligheid en eenduidigheid:
Voorbeeld code:
final class Logger { static let shared = Logger() private init() {} func log(_ message: String) { print(message) } } Logger.shared.log("Voorbeeld van de werking van Singleton")
Belangrijke kenmerken:
Moet je singleton altijd gebruiken voor alle services van de applicatie?
Nee. Singleton is gerechtvaardigd voor truly global state (bijvoorbeeld ApplicationSettings), maar het gebruik ervan voor business-logica services is ongepast: dit leidt tot tight coupling en problemen met unit-testing.
Garandeert static let threadveilige initialisatie van Singleton in Swift?
Ja, vanaf Swift 1.2 (en vanwege de architectuur van de runtime) is static let van nature thread-safe — het wordt één keer geïnitialiseerd, zelfs bij concurrentie van threads.
Kan een singleton geërfd worden?
Nee. Het is beter om de klasse als final te verklaren om overerving te voorkomen — anders kunnen twee instanties van singletons van verschillende subklassen worden gemaakt, wat het idee van het patroon zelf ondermijnt.
Een service voor netwerken is geïmplementeerd via singleton, en de methoden gebruiken globale staat. In unit-tests ontstaat een impliciete afhankelijkheid, het hergebruiken van de service is onmogelijk.
Voordelen:
Nadelen:
Singleton wordt alleen gebruikt voor truly-global entiteit — bijvoorbeeld ApplicationConfig. Alle services ontvangen afhankelijkheden via een expliciete injector.
Voordelen:
Nadelen: