Protokollorienterad programmering i Swift 2

Introduktion

Med release av Swift 2 lade Apple ett antal nya funktioner och funktioner till Swift-programmeringsspråket. En av de viktigaste var dock en översyn av protokoll. Den förbättrade funktionaliteten som är tillgänglig med Swift-protokoll möjliggör en ny typ av programmering, protokollinriktad programmering. Detta står i kontrast till den mer vanliga objektorienterade programmeringsstil som många av oss är vana vid.

I denna handledning kommer jag att visa dig grunderna i protokollinriktad programmering i Swift och hur den skiljer sig från objektorienterad programmering.

förutsättningar

Denna handledning kräver att du kör Xcode 7 eller högre, vilket inkluderar stöd för version 2 i Swift programmeringsspråket.

1. Protokoll Basics

Om du inte redan är bekant med protokoll är de ett sätt att utvidga funktionaliteten hos en befintlig klass eller struktur. Ett protokoll kan ses som en ritning eller ett gränssnitt som definierar en uppsättning egenskaper och metoder. En klass eller struktur som överensstämmer med ett protokoll krävs för att fylla i dessa egenskaper och metoder med respektive värden och implementeringar.

Det bör också noteras att någon av dessa egenskaper och metoder kan betecknas som valfri, vilket innebär att överensstämmande typer inte krävs för att implementera dem. En protokolldefinition och klassöverensstämmelse i Swift kan se ut så här:

protokoll Välkommen var welcomeMessage: String get set valfri func welcome () class Välkommen: Välkommen var welcomeMessage = "Hej världen!" func välkommen () print (welcomeMessage)

2. Ett exempel

För att börja öppna Xcode och skapa en ny lekplats för antingen IOS eller OS X. När Xcode har skapat lekplatsen, ersätt dess innehåll med följande:

protokoll Körbar var topSpeed: Int get protokoll Reversibel var reverseSpeed: Int get protokoll Transport var seatCount: Int get

Vi definierar tre protokoll, som alla innehåller en egendom. Därefter skapar vi en struktur som överensstämmer med dessa tre protokoll. Lägg till följande kod på lekplatsen:

struktur Bil: Körbar, Vändbar, Transport var topSpeed ​​= 150 var reverseSpeed ​​= 20 var seatCount = 5

Du kanske har märkt att istället för att skapa en klass som överensstämmer med dessa protokoll skapade vi en struktur. Vi gör detta för att undvika ett av de typiska problemen som är föremål för objektorienterad programmering, objektreferenser.

Tänk dig att du har två objekt, A och B. A skapar viss data på egen hand och innehåller en hänvisning till den data. A delar sedan dessa data med B genom referens, vilket innebär att båda objekten har en hänvisning till samma objekt. Utan att veta, ändrar B uppgifterna på något sätt.

Även om det här inte verkar som ett stort problem kan det vara när A inte förväntade sig att data skulle ändras. Objekt A kan hitta data som inte vet hur man hanterar eller hanterar. Detta är en vanlig risk för objektreferenser.

I Swift går strukturer av värde snarare än genom referens. Det betyder att i det ovanstående exemplet, om data som skapades av A packades som en struktur i stället för ett objekt och delades med B, skulle data kopieras istället för att delas genom referens. Detta skulle då resultera i att både A och B har sin egen unika kopia av samma data. En ändring som gjorts av B skulle inte påverka kopian som hanteras av A.

Bryter upp körbarReversibel, och Transport Komponenter i enskilda protokoll möjliggör också en större anpassning än traditionell klassärv. Om du har läst min första handledning om det nya GameplayKit-ramverket i IOS 9, så är den här protokollinriktade modellen mycket lik den strukturen Entities and Components som används i GameplayKit-ramverket.

Genom att anta detta tillvägagångssätt kan egna datatyper erhålla funktion från flera källor snarare än en enda superklass. Med tanke på vad vi har hittills kunde vi skapa följande klasser:

  • en klass med komponenter i körbar och Reversibel protokoll
  • en klass med komponenter i körbar och transportabla protokoll
  • en klass med komponenter i Reversibel och transportabla protokoll

Med objektorienterad programmering skulle det mest logiska sättet att skapa dessa tre klasser vara att ärva från en superklass som innehåller komponenterna i alla tre protokollen. Detta tillvägagångssätt leder emellertid till att superklassen är mer komplicerad än den behöver och var och en av underklassen ärver mer funktionalitet än den behöver.

3. Protokollförlängningar

Allt jag visat dig hittills har varit möjligt i Swift sedan dess släppt 2014. Dessa samma protokollorienterade begrepp kunde till och med ha tillämpats på Objective-C-protokoll. På grund av de begränsningar som brukade existera på protokoll var dock sann protokollinriktad programmering inte möjlig förrän ett antal nyckelfunktioner fanns till Swift-språket i version 2. En av de viktigaste av dessa funktioner är protokollförlängningar, Inklusive villkorliga förlängningar.

För det första, låt oss förlänga körbar protokoll och lägg till en funktion för att avgöra om en viss körbar är snabbare än en annan. Lägg till följande på din lekplats:

förlängning Körbar func isFasterThan (item: Körbar) -> Bool return self.topSpeed> item.topSpeed låt sedan = Bil () låt sportCar = Bil (topphastighet: 250, bakåtSpeed: 25, seatCount: 2) sedan.isFasterThan (sportbil)

Du kan se att när lekplatsens kod exekveras, matar den ut ett värde på falsksom din sedan bilen har en standard Maxfart av 150, vilket är mindre än sportbil.

Du kanske har märkt att vi tillhandahöll en funktion definition snarare än en funktion deklaration. Detta verkar konstigt, eftersom protokoll endast ska innehålla deklarationer. Höger? Detta är ett annat mycket viktigt inslag i protokollförlängningar i Swift 2, standardbeteenden. Genom att utöka ett protokoll kan du tillhandahålla en standardimplementering för funktioner och beräknade egenskaper så att klasser som överensstämmer med protokollet inte behöver.

Därefter kommer vi att definiera en annan körbar protokollförlängning, men den här gången definierar vi bara den för värdetyper som också överensstämmer med Reversibel protokoll. Denna förlängning innehåller då en funktion som bestämmer vilket objekt som har bättre hastighetsintervall. Vi kan uppnå detta med följande kod:

förlängning Körbar var Själv: Återvändbar func hasLargerRangeThan (föremål: Själv) -> Bool return (self.topSpeed ​​+ self.reverseSpeed)> (item.topSpeed ​​+ item.reverseSpeed) sportCar.hasLargerRangeThan

De Själv nyckelord, stavat med en huvudstad "S", används för att representera klassen eller strukturen som överensstämmer med protokollet. I ovanstående exempel Själv sökord representerar Bil strukturera.

Efter att ha kört lekplatsens kod, kommer Xcode att mata resultaten i sidofältet till höger som visas nedan. Anteckna det sportbil har ett större utbud än sedan.

4. Arbeta med Swift Standard Library

Medan du definierar och förlänger dina egna protokoll kan det vara mycket användbart, den verkliga effekten av protokollförlängningar visar när du arbetar med Swift-standardbiblioteket. Detta låter dig lägga till egenskaper eller funktioner i befintliga protokoll, t.ex. CollectionType (används för saker som arrays och ordböcker) och Equatable (att kunna bestämma när två objekt är lika eller inte). Med villkorliga protokollförlängningar kan du också tillhandahålla mycket specifik funktionalitet för en viss typ av objekt som överensstämmer med ett protokoll.

På vår lekplats kommer vi att förlänga CollectionType protokoll och skapa två metoder, en för att få den genomsnittliga topphastigheten för bilar i en Bil array och en annan för den genomsnittliga omvänd hastigheten. Lägg till följande kod på din lekplats:

förlängning CollectionType där Self.Generator.Element: Drivable func averageTopSpeed ​​() -> Int var totalt = 0, räknat = 0 för objekt i sig total + = item.topSpeed ​​count ++ returnera (totalt / räknat) func averageReverseSpeed(antal: T) -> Int var totalt = 0, räknat = 0 för objekt i objekt total + = item.reverseSpeed ​​count ++ returnera (totalt / räknat) låt bilar = [Bil (), sedan, sportCar] bilar .averageTopSpeed ​​() averageReverseSpeed ​​(bilar)

Den protokollförlängning som definierar averageTopSpeed Metoden utnyttjar villkorade förlängningar i Swift 2. Däremot averageReverseSpeed funktion vi definierar direkt under det är ett annat sätt att uppnå ett liknande resultat med användning av Swift generics. Jag föredrar personligen städaren CollectionType protokollförlängning, men det är upp till personliga preferenser.

I båda funktionerna vierer vi genom matrisen, lägger upp det totala beloppet och returnerar sedan genomsnittsvärdet. Observera att vi manuellt håller en räkning av objekten i matrisen, för när du arbetar med CollectionType snarare än vanligt Array skriv objekt, räkna egendom är a Self.Index.Distance skriv värdet istället för en int.

När din lekplats har exekverat all denna kod, bör du se en genomsnittlig topphastighet på 183 och en genomsnittlig omvänd hastighet på 21.

5. Betydelsen av klasser

Trots att protokollinriktad programmering är ett mycket effektivt och skalbart sätt att hantera din kod i Swift finns det fortfarande helt giltiga skäl att använda klasser när man utvecklar i Swift:

Bakåtkompatibilitet

Majoriteten av iOS, watchOS och tvOS SDKs skrivs i Objective-C, med hjälp av ett objektorienterat tillvägagångssätt. Om du behöver interagera med någon av de API-er som ingår i dessa SDK-er, är du tvungen att använda de klasser som definieras i dessa SDK.

Hänvisning till en extern fil eller artikel

Swift-kompilatorn optimerar livslängden för objekt baserat på när och var de används. Stabiliteten i klassbaserade objekt innebär att dina referenser till andra filer och objekt kommer att förbli konsekventa.

Objektreferenser

Objektreferenser är exakt vad du behöver ibland, till exempel om du matar information till ett visst objekt, till exempel en grafikåtergivare. Att använda klasser med implicit delning är viktigt i situationer som detta, eftersom du måste vara säker på att den renderare du skickar data till är fortfarande samma renderare som tidigare.

Slutsats

Förhoppningsvis i slutet av denna handledning kan du se potentialen i protokollinriktad programmering i Swift och hur den kan användas för att effektivisera och utöka din kod. Medan denna nya kodningsmetod inte helt ersätter objektorienterad programmering, ger den ett antal mycket användbara nya möjligheter.

Från standardbeteenden till protokollförlängningar kommer protokollinriktad programmering i Swift att antas av många framtida API och kommer helt att förändra hur vi tänker på mjukvaruutveckling.

Som alltid, var noga med att lämna dina kommentarer och feedback i kommentarerna nedan.