Protokollorientert programmering i Swift 2

Introduksjon

Med utgivelsen av Swift 2 la Apple en rekke nye funksjoner og evner til Swift programmeringsspråket. En av de viktigste var imidlertid en overhaling av protokoller. Den forbedrede funksjonaliteten som er tilgjengelig med Swift-protokoller, tillater en ny type programmering, protokoll-orientert programmering. Dette er i kontrast til den mer vanlige objektorienterte programmeringsstilen som mange av oss er vant til.

I denne opplæringen skal jeg vise deg grunnleggende om protokollorientert programmering i Swift og hvordan det skiller seg fra objektorientert programmering.

Forutsetninger

Denne opplæringen krever at du kjører Xcode 7 eller høyere, som inkluderer støtte for versjon 2 i Swift programmeringsspråket.

1. Protokoll Grunnleggende

Hvis du ikke allerede er kjent med protokoller, er de en måte å forlenge funksjonaliteten til en eksisterende klasse eller struktur. En protokoll kan betraktes som et blåkopi eller grensesnitt som definerer et sett med egenskaper og metoder. En klasse eller struktur som samsvarer med en protokoll er nødvendig for å fylle ut disse egenskapene og metodene med henholdsvis verdier og implementeringer.

Det bør også bemerkes at noen av disse egenskapene og metodene kan betegnes som valgfrie, hvilket betyr at det ikke er nødvendig med samsvarse typer for å implementere dem. En protokolldefinisjon og klasseoverensstemmelse i Swift kan se slik ut:

protokoll Velkommen var velkommenMessage: String settes valgfri func welcome () klasse Velkommen: Velkommen var welcomeMessage = "Hello World!" func velkommen () print (welcomeMessage)

2. Et eksempel

For å starte, åpne Xcode og opprett en ny lekeplass for enten IOS eller OS X. Når Xcode har opprettet lekeplassen, må du erstatte innholdet med følgende:

protokoll Kjørbar var topSpeed: Int get protokoll Reversibel var reverseSpeed: Int get protokoll Transport var seatCount: Int get

Vi definerer tre protokoller, som hver inneholder en eiendom. Deretter oppretter vi en struktur som samsvarer med disse tre protokollene. Legg til følgende kode på lekeplassen:

Strukturbil: Kjørbar, reversibel, Transport var topSpeed ​​= 150 var reverseSpeed ​​= 20 var setCount = 5

Du har kanskje lagt merke til at i stedet for å lage en klasse som samsvarer med disse protokollene, opprettet vi en struktur. Vi gjør dette for å unngå en av de typiske problemene som er knyttet til objektorientert programmering, objektreferanser.

Tenk for eksempel at du har to objekter, A og B. A lager noen data alene og holder en referanse til dataene. En da deler disse dataene med B ved referanse, noe som betyr at begge objekter har en referanse til det samme objektet. Uten å vite, endrer B dataene på en eller annen måte.

Selv om dette ikke virker som et stort problem, kan det være når A ikke forventer at dataene skal endres. Objekt A kan finne data som den ikke vet hvordan man skal håndtere eller håndtere. Dette er en vanlig risiko for objektreferanser.

I Swift blir strukturer bestått av verdi heller enn ved henvisning. Dette betyr at i det ovennevnte eksempelet, hvis dataene som ble opprettet av A, ble pakket som en struktur i stedet for et objekt og delt med B, ville dataene kopieres i stedet for deles ved referanse. Dette vil da resultere i at både A og B har sin egen unike kopi av det samme datatykket. En endring gjort av B ville ikke påvirke kopien som forvaltes av A.

Bryter opp kjørbarvendbar, og Transportere Komponenter i individuelle protokoller tillater også større grad av tilpasning enn tradisjonell klassearv. Hvis du har lest min første opplæring om det nye GameplayKit-rammeverket i IOS 9, så er denne protokoll-orienterte modellen svært lik Entities and Components-strukturen som brukes i GameplayKit-rammen.

Ved å vedta denne tilnærmingen kan egendefinerte datatyper arve funksjonalitet fra flere kilder i stedet for en enkelt superklasse. Med tanke på hva vi har så langt, kan vi lage følgende klasser:

  • en klasse med komponenter av kjørbar og vendbar protokoller
  • en klasse med komponenter av kjørbar og Transportable protokoller
  • en klasse med komponenter av vendbar og Transportable protokoller

Med objektorientert programmering vil den mest logiske måten å opprette disse tre klassene være å arve fra en superklasse som inneholder komponentene i alle tre protokollene. Denne tilnærmingen resulterer imidlertid i at superklassen blir mer komplisert enn den må være, og hver av underklassene arver mer funksjonalitet enn den trenger.

3. Protokollutvidelser

Alt jeg har vist deg så langt, har vært mulig i Swift helt siden utgivelsen i 2014. Disse samme protokoll-orienterte konseptene kunne til og med vært brukt til Objective-C protokoller. På grunn av begrensningene som eksisterte på protokoller, var sann protokoll-orientert programmering imidlertid ikke mulig før en rekke viktige funksjoner ble lagt til Swift-språket i versjon 2. En av de viktigste av disse funksjonene er protokollutvidelser, gjelder også betingede utvidelser.

For det første, la oss forlenge kjørbar protokoll og legge til en funksjon for å avgjøre om en bestemt kjørbar er raskere enn en annen. Legg til følgende på lekeplassen din:

forlengelse Kjørbar func isFasterThan (element: Kjørbar) -> Bool return self.topSpeed> item.topSpeed la sedan = Bil () la sportsCar = Bil (toppSpeed: 250, reverseSpeed: 25, seatCount: 2) sedan.isFasterThan (sportsbil)

Du kan se at når lekeplassens kode utføres, gir den en verdi på falsksom din sedan bilen har en standard toppfart av 150, som er mindre enn sportsbil.

Du har kanskje lagt merke til at vi har gitt en funksjon definisjon snarere enn en funksjon erklæring. Dette virker rart, fordi protokoller bare skal inneholde erklæringer. Ikke sant? Dette er et annet svært viktig trekk ved protokollutvidelser i Swift 2, standard oppførsel. Ved å utvide en protokoll kan du angi en standardimplementering for funksjoner og beregnede egenskaper, slik at klasser som overholder protokollen ikke må.

Deretter skal vi definere en annen kjørbar protokollutvidelse, men denne gangen definerer vi bare den for verdittyper som også samsvarer med vendbar protokoll. Denne utvidelsen vil da inneholde en funksjon som bestemmer hvilken gjenstand som har bedre hastighetsområde. Vi kan oppnå dette med følgende kode:

forlengelse Kjørbar hvor Selv: Reversibel func hasLargerRangeThan (element: Selv) -> Bool return (selvoppstartspedal + self.reverseSpeed)> (item.topSpeed ​​+ item.reverseSpeed) sportsCar.hasLargerRangeThan (sedan)

De Selv Søkeord, stavet med en hovedstad "S", brukes til å representere klassen eller strukturen som samsvarer med protokollen. I eksempelet ovenfor er det Selv søkeord representerer Bil struktur.

Etter å ha kjørt lekeplassens kode, vil Xcode sende resultatene i sidefeltet til høyre som vist nedenfor. Noter det sportsbil har et større utvalg enn sedan.

4. Arbeide med Swift Standard Library

Mens du definerer og utvider dine egne protokoller, kan det være veldig nyttig, den virkelige kraften til protokollutvidelser viser når du arbeider med Swift-standardbiblioteket. Dette lar deg legge til egenskaper eller funksjoner til eksisterende protokoller, for eksempel CollectionType (brukes til ting som arrays og ordbøker) og equatable (å kunne bestemme når to objekter er like eller ikke). Med betingede protokollutvidelser kan du også gi svært spesifikk funksjonalitet for en bestemt type objekt som samsvarer med en protokoll.

På vår lekeplass skal vi forlenge CollectionType protokoll og opprette to metoder, en for å få den gjennomsnittlige topphastigheten til biler i en Bil array og en annen for den gjennomsnittlige omvendt hastighet. Legg til følgende kode på lekeplassen din:

utvidelse CollectionType hvor Self.Generator.Element: Drivable func averageTopSpeed ​​() -> Int var totalt = 0, telle = 0 for element i seg selv total + = item.topSpeed ​​count ++ retur (total / telle) func averageReverseSpeed(elementer: T) -> Int var totalt = 0, telle = 0 for element i elementene total + = item.reverseSpeed ​​count ++ retur (totalt / telle) la biler = [Car (), sedan, sportsCar] biler .AverageTopSpeed ​​() gjennomsnittligReverseSpeed ​​(biler)

Protokollutvidelsen som definerer averageTopSpeed Metoden utnytter betingede forlengelser i Swift 2. I kontrast til averageReverseSpeed funksjon definerer vi direkte under det er en annen måte å oppnå et lignende resultat ved å bruke Swift generics. Jeg personlig foretrekker renere ser CollectionType protokollutvidelse, men det er opp til personlig preferanse.

I begge funksjonene vierer vi gjennom arrayet, legger opp det totale beløpet, og returnerer deretter gjennomsnittsverdien. Vær oppmerksom på at vi manuelt holder teller av elementene i matrisen, fordi når du arbeider med CollectionType heller enn vanlig Array skriv elementer, telle Eiendommen er en Self.Index.Distance skriv verdien i stedet for en int.

Når lekeplassen har utført all denne koden, bør du se en gjennomsnittlig topphastighet på utgangssiden 183 og en gjennomsnittlig omvendt hastighet på 21.

5. Betydningen av klasser

Til tross for at protokollorientert programmering er en svært effektiv og skalerbar måte å administrere koden i Swift, er det fortsatt helt gyldige grunner til at du bruker klasser når du utvikler deg i Swift:

Bakoverkompatibilitet

De fleste iOS, watchOS og tvOS SDK er skrevet i Objective-C, ved hjelp av en objektorientert tilnærming. Hvis du trenger å samhandle med noen av APIene som er inkludert i disse SDKene, må du bruke klassene som er definert i disse SDKene.

Henvise en ekstern fil eller en gjenstand

Swift-kompilatoren optimaliserer levetiden til objekter basert på når og hvor de brukes. Stabiliteten til klassebaserte objekter betyr at referanser til andre filer og gjenstander forblir konsistente.

Objektreferanser

Objektreferanser er akkurat det du trenger til tider, for eksempel hvis du mater informasjon til en bestemt gjenstand, for eksempel en grafikkgjenstander. Å bruke klasser med implisitt deling er viktig i situasjoner som dette, fordi du må være sikker på at rendereren du sender dataene til, fortsatt er den samme rendereren som før.

Konklusjon

Forhåpentligvis ved slutten av denne opplæringen kan du se potensialet for protokollorientert programmering i Swift og hvordan det kan brukes til å strømlinjeforme og utvide koden. Selv om denne nye metoden for koding ikke helt erstatter objektorientert programmering, kommer det med en rekke svært nyttige nye muligheter.

Fra standardadferd til protokollutvidelser vil protokollorientert programmering i Swift bli vedtatt av mange fremtidige APIer og vil helt endre måten vi tenker på utvikling av programvare.

Som alltid, vær sikker på å legge igjen dine kommentarer og tilbakemeldinger i kommentarene nedenfor.