Protocolul orientat de programare în Swift 2

Introducere

Odată cu lansarea Swift 2, Apple a adăugat o gamă de noi caracteristici și capabilități în limba de programare Swift. Unul dintre cele mai importante, totuși, a fost o revizuire a protocoalelor. Funcționalitatea îmbunătățită disponibilă cu protocoalele Swift permite un nou tip de programare, programare orientată pe protocol. Acest lucru este în contrast cu obișnuitul stil de programare orientat spre obiect, pe care mulți dintre noi suntem obișnuiți.

În acest tutorial, vă voi arăta elementele de bază ale programării orientate pe protocol în Swift și cum diferă de programarea orientată pe obiect.

Cerințe preliminare

Acest tutorial cere să executați Xcode 7 sau o versiune ulterioară, care include suport pentru versiunea 2 a limbajului de programare Swift.

1. Bazele protocolului

Dacă nu sunteți deja familiarizați cu protocoalele, acestea sunt o modalitate de a extinde funcționalitatea unei clase sau structuri existente. Un protocol poate fi considerat ca un model sau o interfață care definește un set de proprietăți și metode. O clasă sau o structură care este conformă unui protocol este necesară pentru a completa aceste proprietăți și metode cu valorile și respectiv implementările.

De asemenea, trebuie remarcat faptul că oricare dintre aceste proprietăți și metode pot fi desemnate ca opționale, ceea ce înseamnă că nu sunt necesare tipuri corespunzătoare pentru a le pune în aplicare. O definiție a protocolului și conformitatea în clasă în Swift ar putea arăta astfel:

protocol Welcome var welcomeMessage: String get set optional func welcome () clasa Welcomer: Welcome var welcomeMessage = "Hello World!" func welcome () print (welcomeMessage)

2. Un exemplu

Pentru a începe, deschideți Xcode și creați un nou loc de joacă pentru iOS sau OS X. Odată ce Xcode a creat spațiul de joacă, înlocuiți conținutul cu următoarele:

protocol var topSpeed: Int get Protocolul reversibil var reverseSpeed: Int get protocol var seatCount: Int get

Definim trei protocoale, fiecare conținând o proprietate. Apoi, vom crea o structură care să respecte aceste trei protocoale. Adăugați următorul cod la locul de joacă:

struct Masina: Drivable, Reversible, Transport var topSpeed ​​= 150 var reverseSpeed ​​= 20 var seatCount = 5

S-ar putea să fi observat că în loc să creăm o clasă care să respecte aceste protocoale, am creat o structură. Facem acest lucru pentru a evita una dintre problemele tipice inerente programării orientate obiect, referințe obiect.

Imaginați-vă, de exemplu, că aveți două obiecte, A și B. A creează unele date pe cont propriu și păstrează o referință la acele date. A, apoi împarte aceste date cu B prin referință, ceea ce înseamnă că ambele obiecte au o referință la același obiect. Fără a ști, B schimba datele într-un fel.

Deși acest lucru nu pare a fi o problemă mare, poate fi atunci când A nu se aștepta ca datele să fie modificate. Obiectul A poate găsi date despre care nu știe să facă sau să se ocupe. Acesta este un risc comun al trimiterilor de obiecte.

În Swift, structurile sunt trecute valoare mai degrabă decât prin referinţă. Aceasta înseamnă că, în exemplul de mai sus, dacă datele create de către A au fost ambalate ca o structură în locul unui obiect și partajate cu B, datele s-ar copia în loc să fie partajate prin referință. Acest lucru ar determina apoi ca atât A cât și B să aibă propria lor copie unică a aceleiași date. O modificare făcută de B nu ar afecta copia gestionată de A.

Breaking the drivableReversibil, și Transport componentele în protocoalele individuale permite, de asemenea, un nivel mai ridicat de personalizare decât moștenirea tradițională a claselor. Dacă ați citit primul tutorial despre noul cadru GameplayKit din iOS 9, atunci acest model orientat pe protocol este foarte asemănător cu structura Entities and Components utilizată în cadrul GameplayKit.

Prin adoptarea acestei abordări, tipurile personalizate de date pot moșteni funcționalitatea din mai multe surse, mai degrabă decât o singură superclasă. Ținând cont de ceea ce am obținut până acum, am putea crea următoarele clase:

  • o clasă cu componente ale drivable și Reversibil protocoale
  • o clasă cu componente ale drivable și Transportabil protocoale
  • o clasă cu componente ale Reversibil și Transportabil protocoale

Cu ajutorul programării orientate pe obiecte, cea mai logică modalitate de a crea aceste trei clase ar fi să moștenim dintr-o superclasă care conține componentele celor trei protocoale. Această abordare are totuși ca superclajul să fie mai complicat decât trebuie să fie și fiecare subclasă moștenind mai multă funcționalitate decât are nevoie.

3. Extensii de protocol

Tot ce ți-am arătat până acum a fost posibil în Swift chiar de la lansarea sa în 2014. Aceleași concepte orientate pe protocol ar fi putut fi aplicate și în protocoalele Obiectiv-C. Datorită limitărilor existente pe protocoale, totuși, o programare adevărată bazată pe protocol nu a fost posibilă până când nu s-au adăugat mai multe caracteristici cheie în limba Swift în versiunea 2. Una dintre cele mai importante dintre aceste caracteristici este extensii de protocol, inclusiv prelungiri condiționate.

În primul rând, să extindeți drivable protocol și adăugați o funcție pentru a determina dacă este sau nu un anumit drivable este mai rapid decât altul. Adăugați următoarele la locul de joacă:

Extensie Drivable func isFasterThan (item: Drivable) -> Bool retur self.topSpeed> item.topSpeed sedan = car () let sportCar = Mașină (topSpeed: 250, reverseSpeed: 25, sedan.isFasterThan (mașină sport)

Puteți vedea că, atunci când codul locului de joacă este executat, acesta emite o valoare de falsca al tau limuzină mașina are implicit viteza maxima de 150, care este mai mică decât mașină sport.

S-ar putea să fi observat că am oferit o funcție definiție mai degrabă decât o funcție declaraţie. Acest lucru pare ciudat, deoarece protocoalele trebuie doar să conțină declarații. Dreapta? Aceasta este o altă caracteristică foarte importantă a extensiilor de protocol în Swift 2, implicite. Prin extinderea unui protocol, puteți oferi o implementare implicită pentru funcții și proprietăți calculate, astfel încât clasele conforme protocolului să nu trebuiască.

Apoi, vom defini altul drivable protocolul de extensie, dar de data aceasta îl vom defini numai pentru tipurile de valori care sunt, de asemenea, conforme cu Reversibil protocol. Această extensie va conține apoi o funcție care determină ce obiect are cel mai bun interval de viteză. Putem realiza acest lucru cu următorul cod:

Extensie Drivable unde Self: Reversible func hasLargerRangeThan (element: Self) -> Bool return (self.topSpeed ​​+ self.reverseSpeed)>

 De sine cuvântul cheie, scris cu un capitol "S", este folosit pentru a reprezenta clasa sau structura care se conformează protocolului. În exemplul de mai sus, De sine cuvântul cheie reprezintă Mașină structura.

După rularea codului locului de joacă, Xcode va afișa rezultatele în bara laterală în partea dreaptă, după cum se arată mai jos. Rețineți că mașină sport are o gamă mai mare decât limuzină.

4. Lucrul cu Biblioteca Standard Swift

În timp ce definirea și extinderea protocoalelor proprii pot fi foarte utile, adevărata putere a extensiilor de protocol arată când se lucrează cu biblioteca standard Swift. Aceasta vă permite să adăugați proprietăți sau funcții la protocoalele existente, cum ar fi CollectionType (folosit pentru lucruri precum matrice și dicționare) și Equatable (fiind capabil să determine când două obiecte sunt egale sau nu). Cu extensii de protocol condiționate, puteți oferi, de asemenea, o funcționalitate foarte specifică pentru un anumit tip de obiect care este conform cu un protocol.

În terenul nostru de joacă, vom extinde CollectionType protocol și a crea două metode, una pentru a obține viteza medie maximă a mașinilor într-un Mașină și o viteză medie inversă. Adăugați următorul cod la locul de joacă:

extensie TypeType unde Self.Generator.Element: Drivable func medieTopSpeed ​​() -> Int var total = 0, count = 0 pentru elementul în sine total + = item.topSpeed ​​count ++ return (total / count) func averageReverseSpeed(elemente: T) -> Int var total = 0, count = 0 pentru elementul în articole total + = item.reverseSpeed ​​count ++ return (total / count) cars = .averageTopSpeed ​​() averageReverseSpeed ​​(masini)

Protocolul de extensie care definește averageTopSpeed Metoda profită de extensiile condiționate în Swift 2. În schimb, averageReverseSpeed funcția pe care o definim direct sub aceasta este o altă modalitate de a obține un rezultat similar utilizând genericele Swift. Eu personal prefer curatorul cautati CollectionType extinderea protocolului, dar este de preferat personal.

În ambele funcții, iterăm prin matrice, adăugăm suma totală și apoi returnez valoarea medie. Rețineți că păstrăm manual numărul elementelor din matrice, deoarece atunci când lucrați cu ele CollectionType mai degrabă decât regulat mulțime articolele de tip, numara proprietatea este a Self.Index.Distance tip mai degrabă decât o valoare Int.

Odată ce loc de joacă a executat tot acest cod, ar trebui să vedeți o viteză maximă de ieșire medie de 183 și o viteză medie inversă de 21.

5. Importanța claselor

În ciuda programării orientate pe protocol fiind o modalitate foarte eficientă și scalabilă de a vă gestiona codul în Swift, există încă motive perfect valabile pentru utilizarea cursurilor atunci când se dezvoltă în Swift:

Compatibilitate înapoi

Majoritatea SDK-urilor iOS, watchOS și tvOS sunt scrise în Obiectiv-C, folosind o abordare orientată pe obiecte. Dacă aveți nevoie să interacționați cu oricare dintre API-urile incluse în aceste SDK-uri, sunteți obligat să utilizați clasele definite în aceste SDK-uri.

Referindu-se la un fișier sau un element extern

Compilatorul Swift optimizează durata de viață a obiectelor în funcție de momentul și locul unde sunt utilizate. Stabilitatea obiectelor de clasă înseamnă că trimiterile la alte fișiere și elemente vor rămâne în concordanță.

Obiecte de referință

Referințele obiectului sunt exact ceea ce aveți nevoie, uneori, de exemplu, dacă alimentați informațiile într-un anumit obiect, cum ar fi un renderer grafic. Folosirea clasei cu partajare implicită este importantă în astfel de situații, pentru că trebuie să fii sigură că randarea la care trimiteți datele este în continuare același randator ca și înainte.

Concluzie

Sperăm că până la sfârșitul acestui tutorial puteți vedea potențialul de programare orientat pe protocol în Swift și cum poate fi folosit pentru a simplifica și extinde codul. În timp ce această nouă metodologie de codificare nu va înlocui în întregime programarea orientată pe obiecte, ea va aduce o serie de noi posibilități foarte utile.

De la comportamentele implicite la extensiile de protocol, programarea orientată pe protocol în Swift va fi adoptată de mai multe API viitoare și va schimba complet modul în care ne gândim la dezvoltarea de software.

Ca întotdeauna, asigurați-vă că părăsiți comentariile și comentariile dvs. în comentariile de mai jos.

Cod