skriven av Reinder de Vries den 10 januari 2019 i apputveckling, Swift
en singleton är en klass av vilken exakt en instans existerar, som kan nås globalt. Hur skapar du en singleton i Swift? Och varför borde eller borde du inte?
i denna handledning kommer vi att dyka in i singletons i Swift. Du lär dig vad singleton designmönstret är och varför det är användbart. Vi diskuterar syntaxen för att skapa singletons i Swift. Och vi kommer in i bra och dåliga användningsfall för singletons.
redo? Nu går vi.
- Vad Är En Singleton?
- Kodning Av En Singleton I Swift
- När Ska Man Använda Singletons
- Vidare Läsning
Vad Är En Singleton?
en singleton är en klass av vilken endast en instans existerar. Några exempel:
- ett företag har bara en
CEO
- en API-klass har bara en seriebegäranskö
- ett operativsystem har bara ett filsystem
- en solsystemkropp kretsar kring en gravitationspunkt
- en app som gör I/O har bara en standard
FileManager
- ett flygplan har bara ett flygdäck
det andra attributet för en singleton är att den har en global åtkomstpunkt. Du kan komma åt en singleton, t.ex. ring funktioner på den, var som helst i appens kod.
så, för att sammanfatta:
- en singleton är en klass som bara har en instans
- den kan nås globalt, dvs var som helst i din kod
i praktisk iOS-utveckling använder du singletons ofta. Typiska klasser som NotificationCenter
, UserDefaults
, SKPaymentQueue
och FileManager
har shared
eller default
egenskaper som är singletons.
vid andra tillfällen kanske du vill skapa en singleton själv. Ett bra användningsfall är en API
– klass som exponerar singleton-instans via dess shared
– egenskap. Du använder API.shared.makeAPICall()
för att komma åt API: et via en enda, enhetlig instans. Detta gör att du till exempel kan hantera API-samtal seriellt.
innan vi diskuterar när singletons bäst används (och när inte), låt oss ta reda på hur man kodar en singleton i Swift.
bli anställd som IOS-utvecklare
lär dig att bygga iOS 14-appar med Swift 5
registrera dig för min iOS-utvecklingskurs och lär dig hur du startar din karriär som professionell iOS-utvecklare.
kodning av en Singleton i Swift
Detta är det bästa sättet att skapa en singleton i Swift:
class API{ static let shared = API() private init() { // Set up API instance }}
och här är hur du använder singleton:
API.shared.doSomething()
vi skapar en API
klass som har en statisk egenskap som heter shared
. Den här egenskapen kan inte ändras när den är inställd, eftersom den är en konstant och den deklareras statiskt.
det betyder att vi kan komma åt egenskapen shared
via klassen API
. Detta kallas ofta en klassfastighet. Jämför detta med en normal instansegenskap, som endast kan nås via en instans av en klass.
det som är intressant är att egenskapen shared
initierar en instans av API
inom klassen API
. Vi skapar ett API
– objekt som kan nås via klassen API
. Men det finns mer…
klassinitieraren init()
är markerad med private
. Detta private
nyckelord säkerställer att klassen API
endast kan initieras inom klassen API
.
med andra ord kan du inte skapa en instans av API
utanför klassen API
! Detta säkerställer att API
– objektet Vi har skapat är den enda instansen i vår kod. När allt kommer omkring kan du inte skapa mer av det.
och nu har vi säkerställt att API
– klassen överensstämmer med de två attributen för en singleton:
- tack vare den statiska egenskapen
shared
kanAPI
– instansen nås globalt - tack vare
private init()
kanAPI
– klassen inte initieras utanförAPI
– klassen
allt detta kan låta lite abstrakt för dig, så låt oss utöka föregående exempel med lite mer praktisk kod. Här är vad:
API
klassen är mestadels densamma. Det är fortfarande en singleton, och det använder fortfarande de static let shared = API()
och private init()
bitar av kod.
här är vad som har ändrats:
- klassen
API
har nu enisRequestPending
egenskap. Det är här faran börjar… se hurisRequestPending
boolean säkerställer att endast en API-begäran kan göras åt gången? (Observera attisRequestPending
är en instansegenskap.) -
API
klassen har också enmakeAPIRequest()
funktion. Föreställ dig att vi kan använda den här funktionen för att få tillbaka några data från ett webservice API, som Twitter. i funktionen kan du se att en begäran endast kan göras när ingen annan begäran för närvarande väntar. -
API
klassen har också enonReturnAPIRequest()
funktion. Denna funktion anropas när API-begäran returnerar, dvs. online-data har laddats ner till appen.isRequestPending
boolean är inställd påfalse
igen och förfrågningsdata behandlas.
och här är hur vi kan använda API
singleton var som helst i vår kod:
API.shared.makeAPIRequest()
det är något annat vi måste diskutera. Klassen API
hanterar nu något som kallas stat. Du kan se ”staten” som en känsla: du är antingen glad eller du är ledsen, eller du är arg, och så vidare. Du kan växla från ett tillstånd till det andra.
API
klassen kan växla mellan två tillstånd:
- ett tillstånd där
isRequestPending
ärfalse
- ett tillstånd där
isRequestPending
ärtrue
som du lär dig i nästa avsnitt, tillstånd och single kan utlösa alla typer av förödelse på din kod. Hantera staten dåligt är den enskilt största orsaken till singleton missbruk.
När ska man använda Singletons
när använder du singletons? Boken Design Patterns: Elements of återanvändbar objektorienterad programvara av gänget på fyra har följande att säga. Använd singleton-mönstret när:
- det måste finnas exakt en instans av en klass, och den måste vara tillgänglig för klienter från en välkänd åtkomstpunkt
- när den enda instansen ska kunna utökas genom subclassing, och klienter ska kunna använda en utökad instans utan att ändra sin kod
det är komplext, men vad det kokar ner till är:
- använd en singleton när din kod inte kräver mer än en instans av en klass (dvs. VD i företaget)
- och när den måste vara tillgänglig var som helst i din kod (dvs., filsystemet)
ett annat användningsfall är subclassing. En global variabel i din kod kan inte enkelt underklassas, så det är därför du använder en singleton-klass. Dessutom kan singletons enhetstestas med hjälp av beroendeinjektion. Du ersätter API
– instansen med en APIMock
– instans och får möjlighet att enhetstesta API-samtal utan att göra de faktiska nätverksförfrågningarna.
och när använder du inte singletons? För att svara på den frågan måste vi gå tillbaka till den statsprincip som vi diskuterade tidigare.
en vanlig fallgrop för nybörjare iOS utvecklare är att hantera tillstånd och dess beroenden dåligt. Tänk dig att du bygger en app som använder klassen API
som vi arbetade med tidigare.
varje gång du utökar API-klassen klibbar du på fler och fler egenskaper, till exempel:
- en
userID
egenskap som håller reda på den inloggade användaren, närlogin()
API-anropet har gjorts - en
tweets
egenskap med Twitter-data, närgetTweets()
Anropet har gjorts - en
spinner
egenskap med enUIActivityIndicatorView
som du lägger till i en vykontroll när en begäran har startat
först är det mycket meningsfullt att göra. Trots allt kan klassen API
nås var som helst i din kod. Så i Tweet View-kontrollen kan du använda API.shared.tweets
– arrayen, och i Inställningsregulatorn kan du använda userID
för att snabbt berätta för API vars inställningar som ska ändras.
tyvärr är ditt tillstånd nu överallt. Klassen API
har beroenden till en massa klasser som inte är relaterade till API-klassens enda ansvar. Din kod har blivit en skål med spagetti, alla trassliga upp. Koden kan fungera OK, men det är omöjligt att underhålla och förlänga.
Låt oss titta på ett exempel. Funktionen onReturnAPIRequest()
som vi definierade tidigare är på randen av att bli tätt kopplad…
här är vad vi överväger:
-
onReturnAPIRequest()
anropas när en API webservice request returnerar, dvs. när data kommer in i appen. Dessa data måste gå någonstans-en Tweet View Controller till exempel. Hur skickar du data frånAPI
till visningskontrollen? - ett självklart val är att bara skapa en referens till
viewController
iAPI
klassen. När data kommer in kan du koda något somviewController.tweets = tweetsData
. Det här är dålig arkitektur, tyvärr, för nu ärAPI
och view controller tätt kopplade. Det är omöjligt (eller svårt) att enhetstest, och sannolikt att skapa problem vid förlängning antingen klass. - det är bättre att välja en mekanism som inte tätt kopplar ihop båda klasserna. Ett alternativ skulle vara att skicka en stängning till
onReturnAPIRequest()
, som körs när begäran returnerar. Denna stängning kan då innehålla kod för att hantera inkommande data. Ett annat alternativ skulle vara att användaNotificationCenter
för att skicka data till view controller, eller att använda enDatabase
– klass för att hantera data.
singleton designmönstret har fått en del kontroverser, helt enkelt för att det är lätt att missbruka. När du använder singletons, var uppmärksam på tillstånd och beroenden. Bara för att det är lätt att få global tillgång till staten betyder det inte att det är en bra ide.
bli anställd som IOS-utvecklare
lär dig att bygga iOS 14-appar med Swift 5
registrera dig för min iOS-utvecklingskurs och lär dig hur du startar din karriär som professionell iOS-utvecklare.
Vidare läsning
och det är allt som finns till det! Att lära känna singletons är ett värdefullt mål, särskilt om du är intresserad av apparkitektur och systemdesign.