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.

  1. Vad Är En Singleton?
  2. Kodning Av En Singleton I Swift
  3. När Ska Man Använda Singletons
  4. 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:

  1. en singleton är en klass som bara har en instans
  2. 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:

  1. tack vare den statiska egenskapen shared kan API – instansen nås globalt
  2. tack vare private init() kan API – klassen inte initieras utanför API – 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 en isRequestPending egenskap. Det är här faran börjar… se hur isRequestPending boolean säkerställer att endast en API-begäran kan göras åt gången? (Observera att isRequestPending är en instansegenskap.)
  • API klassen har också en makeAPIRequest() 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å en onReturnAPIRequest() 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 är false
  • ett tillstånd där isRequestPending är true

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är login() API-anropet har gjorts
  • en tweets egenskap med Twitter-data, när getTweets() Anropet har gjorts
  • en spinner egenskap med en UIActivityIndicatorView 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ån API till visningskontrollen?
  • ett självklart val är att bara skapa en referens till viewController i API klassen. När data kommer in kan du koda något som viewController.tweets = tweetsData. Det här är dålig arkitektur, tyvärr, för nu är API 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ända NotificationCenter för att skicka data till view controller, eller att använda en Database – 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.

Lämna ett svar

Din e-postadress kommer inte publiceras.