geschreven door Reinder de Vries op 10 januari 2019 in App Development, Swift

een singleton is een klasse waarvan precies één instantie bestaat, die wereldwijd kan worden benaderd. Hoe creëer je een singleton in Swift? En waarom wel of niet?

in deze handleiding duiken we in singletons in Swift. Je leert wat het singleton ontwerppatroon is en waarom het nuttig is. We bespreken de syntaxis voor het maken van singletons in Swift. En we krijgen goede en slechte use cases voor singletons.

klaar? Laten we gaan.

  1. Wat Is Een Singleton?
  2. Een Singleton Coderen In Swift
  3. Wanneer Singletons
  4. Verder Lezen

Wat Is Een Singleton?

een singleton is een klasse waarvan slechts één instantie bestaat. Enkele voorbeelden:

  • een bedrijf heeft slechts één CEO
  • een API-klasse heeft slechts één wachtrij voor seriële Verzoeken
  • een besturingssysteem heeft slechts één bestandssysteem
  • een lichaam van een zonnestelsel draait om één gravitatiepunt
  • een app die I/O heeft slechts één standaard FileManager
  • een vliegtuig heeft slechts één cockpit

de tweede attribuut van een singleton is dat het een wereldwijd toegangspunt heeft. U kunt toegang krijgen tot een singleton, bijvoorbeeld. bel functies op het, vanaf elke locatie in de code van uw app.

zo, om samen te vatten:

  1. een singleton is een klasse met slechts één instantie
  2. het kan globaal worden benaderd, dat wil zeggen overal in uw code

in praktische iOS-ontwikkeling gebruikt u vaak singletons. Typische klassen zoals NotificationCenter, UserDefaults, SKPaymentQueue en FileManager hebben shared of default eigenschappen die singletons zijn.

op andere momenten kunt u zelf een singleton aanmaken. Een goede use case is een API klasse die singleton instance blootlegt via zijn shared eigenschap. U gebruikt API.shared.makeAPICall() om toegang te krijgen tot de API via een enkele, uniforme instantie. Zo kunt u bijvoorbeeld API-oproepen serieel beheren.

voordat we bespreken wanneer singletons het beste worden gebruikt (en wanneer niet), laten we uitzoeken hoe we een singleton in Swift kunnen coderen.

word aangenomen als iOS-ontwikkelaar

leer iOS 14 apps te bouwen met Swift 5

meld je aan voor mijn iOS-ontwikkelcursus en leer hoe je je carrière als professionele iOS-ontwikkelaar kunt beginnen.

een Singleton in Swift coderen

dit is de beste manier om een singleton in Swift aan te maken:

class API{ static let shared = API() private init() { // Set up API instance }}

en zo gebruikt u de singleton:

API.shared.doSomething()

We maken een API klasse aan die één statische eigenschap heeft genaamd shared. Deze eigenschap kan niet worden gewijzigd zodra deze is ingesteld, omdat het een constante is en het statisch is gedeclareerd.

dat betekent dat we de eigenschap shared kunnen benaderen via de klasse API. Dit wordt vaak een klasse-eigenschap genoemd. Vergelijk dit met een normale instantie eigenschap, die alleen toegankelijk is via een instantie van een klasse.

interessant is dat de eigenschap shared een instantie van API initialiseert binnen de klasse API. We zijn een soort van API object aan het maken dat toegankelijk is via de API klasse. Maar er is meer…

de klasse initializer init() is gemarkeerd met private. Dit private sleutelwoord zorgt ervoor dat de API klasse alleen kan worden geïnitialiseerd binnen de API klasse.

met andere woorden, u kunt geen instantie van API aanmaken buiten de API klasse! Dit zorgt ervoor dat het API object dat we hebben gemaakt de enige instantie is in onze code. Je kunt er immers niet meer van maken.

en nu hebben we ervoor gezorgd dat de klasse API voldoet aan de twee attributen van een singleton:

  1. dankzij de statische eigenschap shared, kan de instantie API globaal worden benaderd
  2. dankzij de private init(), kan de klasse API niet worden geïnitialiseerd buiten de klasseAPI

dit klinkt allemaal een beetje abstract voor u, dus laten we het vorige voorbeeld uitbreiden met wat meer praktische code. Dit is wat:

de API klasse is grotendeels hetzelfde. Het is nog steeds een singleton, en het gebruikt nog steeds die static let shared = API() en private init() bits code.

dit is veranderd:

  • de API klasse heeft nu een isRequestPending eigenschap. Dit is waar het gevaar begint … zie hoe de isRequestPending boolean ervoor zorgt dat slechts één API-verzoek tegelijk kan worden gedaan? (Merk op dat isRequestPending een instantie eigenschap is.)
  • de klasse API heeft ook een functie makeAPIRequest(). Stel je voor dat we deze functie kunnen gebruiken om gegevens terug te krijgen van een webdienst API, zoals die van Twitter. In de functie kun je zien dat een verzoek alleen kan worden gedaan als er geen ander verzoek op dit moment in behandeling is.
  • de klasse API heeft ook een functie onReturnAPIRequest(). Deze functie wordt aangeroepen wanneer de API-aanvraag terugkeert, dat wil zeggen online gegevens zijn gedownload in de app. De isRequestPending boolean is opnieuw ingesteld op false, en de aanvraaggegevens worden verwerkt.

en zo kunnen we de API singleton overal in onze code gebruiken:

API.shared.makeAPIRequest()

we moeten nog iets bespreken. De API klasse beheert nu iets genaamd state. Je kunt “toestand” zien als een gevoel: je bent of gelukkig of je bent verdrietig, of je bent boos, enzovoort. U kunt overschakelen van de ene staat naar de andere.

de klasse API kan schakelen tussen twee toestanden:

  • een staat waarin isRequestPending is false
  • een staat waarin isRequestPending is true

zoals je in de volgende sectie zult leren, kunnen state en singletons allerlei schade aanrichten aan je code. Slecht beheer van de staat is de grootste reden voor Singleton misbruik.

wanneer gebruikt u Singletons

wanneer gebruikt u singletons? Het boek Design Patterns: Elements Of herbruikbare Object-georiënteerde Software van The Gang of Four heeft het volgende te zeggen. Gebruik het singleton patroon wanneer:

  • er moet precies één instantie van een klasse, en het moet toegankelijk zijn voor klanten van een bekende access point
  • als de enige instantie moet worden uitgebreid met subclassificering, en klanten moeten kunnen gebruik maken van een uitgebreid exemplaar zonder het aanpassen van de code

Dat is complex, maar waar het op neer komt is:

  • Gebruik een singleton wanneer uw code vereist niet meer dan een instantie van een klasse (d.w.z. de CEO in het bedrijf)
  • En als het moet toegankelijk van overal in de code (d.w.z., het bestandssysteem)

een andere use case is subclassering. Een globale variabele in uw code kan niet gemakkelijk worden gesubclasseerd, dus daarom gebruikt u een singleton-klasse. Bovendien kunnen singletons unit getest worden met behulp van dependency injection. U vervangt de instantie API door een instantie APIMock en krijgt de mogelijkheid om API-oproepen te testen zonder de daadwerkelijke netwerkaanvragen te doen.

en wanneer gebruikt u geen singletons? Om die vraag te beantwoorden, moeten we terug naar het staatsprincipe dat we eerder bespraken.

een veel voorkomende valkuil voor beginnende iOS-ontwikkelaars is om de toestand en de afhankelijkheden ervan slecht te beheren. Stel je voor dat je een app bouwt die gebruik maakt van de API klasse waar we eerder mee gewerkt hebben.

elke keer dat u de API-klasse uitbreidt, u tack op meer en meer eigenschappen, zoals:

  • een userID eigenschap die de ingelogde gebruiker bijhoudt, zodra de login() API-oproep is gedaan
  • een tweets eigenschap met Twitter-gegevens, zodra degetTweets() oproep is gedaan
  • een spinner eigenschap met eenUIActivityIndicatorView die u toevoegt aan een weergavecontroller wanneer een aanvraag is gestart

in het begin, is dit heel logisch. De API klasse kan immers overal in uw code worden benaderd. In de Tweet View Controller kun je de API.shared.tweets array gebruiken en in de Settings Controller kun je userID gebruiken om snel de API te vertellen wiens instellingen moeten worden gewijzigd.

helaas is uw toestand nu overal. De API klasse heeft afhankelijkheden voor een aantal klassen die niet gerelateerd zijn aan de enige verantwoordelijkheid van de API klasse. Je code is een kom spaghetti geworden, helemaal in de war. De code kan goed werken, maar het is onmogelijk te onderhouden en uit te breiden.

laten we een voorbeeld bekijken. De onReturnAPIRequest() functie die we eerder gedefinieerd hebben staat op het punt om nauw met elkaar verbonden te worden …

:

  • de onReturnAPIRequest() wordt aangeroepen wanneer een API-webservice-verzoek terugkeert, dat wil zeggen wanneer gegevens in de app komen. Deze gegevens moeten ergens naartoe gaan-een Tweet View Controller bijvoorbeeld. Hoe geeft u de gegevens van API door aan de weergavecontroller?
  • een voor de hand liggende keuze is om gewoon een verwijzing te maken naar de viewController in de klasse API. Wanneer de gegevens binnenkomen, kunt u iets als viewController.tweets = tweetsDatacoderen. Dit is een slechte architectuur, helaas, omdat nu de API en de beeldcontroller zijn nauw gekoppeld. Het is onmogelijk (of moeilijk) om unit test, en waarschijnlijk problemen te creëren bij het uitbreiden van een van beide klassen.
  • het is beter om een mechanisme te kiezen dat beide klassen niet nauw koppelt. Een optie zou zijn om een afsluiting door te geven aan onReturnAPIRequest(), die wordt uitgevoerd wanneer het verzoek terugkeert. Deze sluiting kan dan code bevatten om de inkomende gegevens af te handelen. Een andere optie zou zijn om NotificationCenter te gebruiken om de gegevens door te geven aan de weergavecontroller, of om een Database klasse te gebruiken om de gegevens te verwerken.

het ontwerppatroon van singleton is controversieel geworden, simpelweg omdat het gemakkelijk te misbruiken is. Bij het gebruik van singletons, wees bewust van de staat en afhankelijkheden. Het is niet omdat het gemakkelijk is om wereldwijd toegang te hebben tot de staat, dat het een goed idee is.

word aangenomen als iOS-ontwikkelaar

leer iOS 14 apps te bouwen met Swift 5

meld je aan voor mijn iOS-ontwikkelcursus en leer hoe je je carrière als professionele iOS-ontwikkelaar kunt beginnen.

verder lezen

en dat is alles wat er is! Het leren kennen van singletons is een waardevolle doelstelling, vooral als je geïnteresseerd bent in app-architectuur en systeemontwerp.

Geef een antwoord

Het e-mailadres wordt niet gepubliceerd.