skrevet af Reinder de Vries den 10. januar 2019 i appudvikling, hurtig

en singleton er en klasse, hvor der findes nøjagtigt en forekomst, der kan fås adgang til globalt. Hvordan opretter du en singleton i hurtig? Og hvorfor skulle eller skulle du ikke?

i denne vejledning dykker vi hurtigt ind i singletoner. Du lærer, hvad singleton design mønster er, og hvorfor det er nyttigt. Vi diskuterer syntaksen for oprettelse af singletoner hurtigt. Og vi kommer ind i gode og dårlige brugssager for singletoner.

klar? Lad os gå.

  1. Hvad Er En Singleton?
  2. Kodning Af En Singleton I Hurtig
  3. Hvornår Skal Man Bruge Singletoner
  4. Yderligere Læsning

Hvad Er En Singleton?

en singleton er en klasse, hvoraf kun en forekomst findes. Et par eksempler:

  • et firma har kun en CEO
  • en API-klasse har kun en seriel anmodningskø
  • et operativsystem har kun et filsystem
  • et solsystemlegeme drejer sig om et tyngdepunkt
  • en app, der gør I/O, har kun en standard FileManager
  • et fly har kun et flydæk

den anden egenskab ved en singleton er, at den har et globalt adgangspunkt. Du kan få adgang til en singleton, f.eks. opkaldsfunktioner på det, hvor som helst i din apps kode.

så for at opsummere:

  1. en singleton er en klasse, der kun har en forekomst
  2. den kan tilgås globalt, dvs.hvor som helst i din kode

i praktisk iOS-udvikling bruger du ofte singletoner. Typiske klasser som NotificationCenter, UserDefaults, SKPaymentQueue og FileManager har shared eller default egenskaber, der er singletoner.

på andre tidspunkter kan du selv oprette en singleton. En god brugssag er en API klasse, der udsætter singleton-forekomst via dens shared ejendom. Du bruger API.shared.makeAPICall() til at få adgang til API ‘ en via en enkelt, samlet forekomst. Dette giver dig for eksempel mulighed for at administrere API-opkald serielt.

før vi diskuterer, hvornår singletoner bedst bruges (og hvornår ikke), lad os finde ud af, hvordan man koder en singleton hurtigt.

bliv ansat som iOS-udvikler

Lær at bygge iOS 14-apps med hurtig 5

Tilmeld dig mit iOS-udviklingskursus, og lær, hvordan du starter din karriere som professionel iOS-udvikler.

kodning af en Singleton i hurtig

dette er den bedste måde at oprette en singleton på hurtig:

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

og her er hvordan du bruger singleton:

API.shared.doSomething()

vi opretter en API klasse, der har en statisk egenskab kaldet shared. Denne egenskab kan ikke ændres, når den er indstillet, fordi den er konstant, og den erklæres statisk.

det betyder, at vi kan få adgang til sharedegenskaben via klassen API. Dette kaldes ofte en klasse ejendom. Sammenlign dette med en normal instansegenskab, som kun kan tilgås via en forekomst af en klasse.

det interessante er, at egenskaben shared initialiserer en forekomst af API inden for klassen API. Vi skaber slags et API objekt, der kan tilgås via API klassen. Men der er mere…

klassens initialisator init()er markeret med private. Dette private søgeord sikrer, at klassen API kun kan initialiseres inden for klassen API.

med andre ord kan du ikke oprette en forekomst af API uden for API klassen! Dette sikrer, at API – objektet, vi har oprettet, er den eneste forekomst i vores kode. Når alt kommer til alt kan du ikke skabe mere af det.

og nu har vi sikret API klassen overholder de to attributter af en singleton:

  1. takket være den statiske egenskab shared kan forekomsten API fås globalt
  2. takket være private init() kan klassen API ikke initialiseres uden for klassen API

dette lyder måske lidt abstrakt for dig, så lad os udvide det forrige eksempel med en mere praktisk kode. Her er hvad:

API klassen er stort set den samme. Det er stadig en singleton, og det bruger stadig de static let shared = API() og private init() bits kode.

her er hvad der er ændret:

  • klassen API har nu en isRequestPending ejendom. Det er her faren begynder… se hvordan isRequestPending boolean sikrer, at kun en API-anmodning kan udføres ad gangen? (Bemærk, at isRequestPending er en instansegenskab.)
  • klassen API har også en makeAPIRequest() funktion. Forestil dig, at vi kan bruge denne funktion til at få nogle data tilbage fra en API, som kvidre. i funktionen kan du se, at en anmodning kun kan foretages, når ingen anden anmodning i øjeblikket afventer.
  • klassen API har også en onReturnAPIRequest() funktion. Denne funktion påberåbes, når API-anmodningen vender tilbage, dvs.online data er blevet hentet ind i appen. isRequestPending boolean er sat til false igen, og anmodningsdataene behandles.

og her er hvordan vi kan bruge API singleton hvor som helst i vores kode:

API.shared.makeAPIRequest()

der er noget andet, vi skal diskutere. Klassen API styrer nu noget, der hedder stat. Du kan se “tilstand” som en følelse: du er enten glad eller du er trist, eller du er vred, og så videre. Du kan skifte fra den ene tilstand til den anden.

API klassen kan skifte mellem to stater:

  • en tilstand, hvor isRequestPending er false
  • en tilstand, hvor isRequestPending er true

som du lærer i næste afsnit, stat og singletoner kan skabe alle slags kaos på din kode. Håndtering af tilstand dårligt er den største enkeltårsag til misbrug af singleton.

Hvornår skal du bruge singletoner

hvornår bruger du singletoner? Bogen Design Patterns: Elements of genanvendeligt objektorienteret program af Gang of Four har følgende at sige. Brug singleton-mønsteret, når:

  • der skal være nøjagtigt en forekomst af en klasse, og den skal være tilgængelig for klienter fra et velkendt adgangspunkt
  • når den eneste forekomst skal udvides ved underklassering, og klienter skal være i stand til at bruge en udvidet forekomst uden at ændre deres kode

det er komplekst, men hvad det koger ned til er:

  • brug en singleton, når din kode ikke kræver mere end en forekomst af en klasse (dvs. administrerende direktør i virksomheden)
  • og når den skal være tilgængelig hvor som helst i din kode (dvs., filsystemet)

en anden brugssag er underklasse. En global variabel i din kode kan ikke let underklassificeres, så det er derfor, du bruger en singleton-klasse. Derudover, singletoner kan enhedstestes ved hjælp af afhængighedsinjektion. Du erstatter forekomsten API med en forekomst APIMock og får mulighed for at enhedstestere API-opkald uden at foretage de faktiske netværksanmodninger.

og hvornår bruger du ikke singletoner? For at besvare dette spørgsmål bliver vi nødt til at gå tilbage til det statsprincip, vi diskuterede tidligere.

en fælles faldgrube for begyndere iOS udviklere er at styre tilstand og dens afhængigheder Dårligt. Forestil dig, at du bygger en app, der bruger den API klasse, vi arbejdede med tidligere.

hver gang du udvider API-klassen, klæber du på flere og flere egenskaber, såsom:

  • a userID egenskab, der holder styr på den loggede bruger, når login() API-opkaldet er foretaget
  • a tweets egenskaben med kvidre data, når getTweets() opkaldet er foretaget
  • en spinner egenskaben med en UIActivityIndicatorView som du føjer til en visningscontroller, når en anmodning er startet

i første omgang giver det meget mening at gøre. Når alt kommer til alt kan API – klassen fås overalt i din kode. Så I Kvidrevisningskontrolleren kan du bruge arrayet API.shared.tweets, og i Indstillingskontrolleren kan du bruge userID til hurtigt at fortælle API ‘ en, hvis indstillinger skal ændres.

Desværre er din tilstand nu overalt. API – klassen har afhængigheder til en flok klasser, der ikke er relateret til API-klassens eneste ansvar. Din kode er blevet en skål spaghetti, alt sammenfiltret. Koden fungerer muligvis OK, men det er umuligt at vedligeholde og udvide.

lad os se på et eksempel. FunktionenonReturnAPIRequest() vi definerede tidligere er på randen af at blive tæt koblet…

her er hvad vi overvejer:

  • onReturnAPIRequest() kaldes, når en API-serviceanmodning vender tilbage, dvs.når data kommer ind i appen. Disse data skal gå et sted – f.eks. Hvordan overfører du dataene fra API til visningscontrolleren?
  • et oplagt valg er at bare oprette en henvisning til viewController i API klassen. Når dataene kommer ind, kan du kode noget som viewController.tweets = tweetsData. Dette er desværre dårlig arkitektur, for nu er API og visningskontrolleren tæt koblet. Det er umuligt (eller svært) at enhedstest, og det vil sandsynligvis skabe problemer, når man udvider en klasse.
  • det er bedre at vælge en mekanisme, der ikke tæt parrer begge klasser. En mulighed ville være at videregive en lukning til onReturnAPIRequest(), som udføres, når anmodningen vender tilbage. Denne lukning kan derefter indeholde kode til at håndtere de indgående data. En anden mulighed ville være at bruge NotificationCenter til at videregive dataene til visningskontrolleren eller at bruge en Database klasse til at håndtere dataene.

singleton-designmønsteret har fået en vis kontrovers, simpelthen fordi det er let at misbruge. Når du bruger singletoner, være opmærksom på tilstand og afhængigheder. Bare fordi det er let at have global adgang til staten, betyder det ikke, at det er en god ide.

bliv ansat som iOS-udvikler

Lær at bygge iOS 14-apps med hurtig 5

Tilmeld dig mit iOS-udviklingskursus, og lær, hvordan du starter din karriere som professionel iOS-udvikler.

yderligere læsning

og det er alt der er til det! At lære singletons at kende er et værdifuldt mål, især hvis du er interesseret i apparkitektur og systemdesign.

Skriv et svar

Din e-mailadresse vil ikke blive publiceret.