Până acum, am acoperit elementele de bază ale limbajului de programare Swift. Dacă ați urmat, ar trebui să aveți acum o înțelegere solidă a variabilelor, constantelor, funcțiilor și închiderilor. Acum este momentul să folosim ceea ce am învățat și să aplicăm aceste cunoștințe structurilor orientate pe obiecte ale lui Swift.
Pentru a înțelege conceptele discutate în acest tutorial, este important să aveți o înțelegere de bază a programării orientate pe obiecte. Dacă nu sunteți familiarizați cu clase, obiecte și metode, vă recomandăm să citiți mai întâi aceste subiecte înainte de a continua cu acest tutorial.
eBook: Programare orientată pe obiecte cu Swift
În această lecție, vom explora blocurile fundamentale de programare orientată obiect în clase și structuri Swift. În Swift, clasele și structurile se simt și se comportă foarte asemănător, dar există o serie de diferențe cheie pe care trebuie să le înțelegeți pentru a evita capcanele comune.
În Obiectiv-C, clasele și structurile sunt foarte diferite. Acest lucru nu este valabil pentru Swift. În Swift, de exemplu, ambele clase și structuri pot avea proprietăți și metode. Spre deosebire de structurile C, structurile din Swift pot fi extinse și pot, de asemenea, să se conformeze protocoalelor.
Întrebarea evidentă este: "Care este diferența dintre clase și structuri?" Vom revizui această întrebare mai târziu în acest tutorial. Să vedem mai întâi cum arată o clasă în Swift.
Înainte de a începe să lucrăm cu clase și structuri, aș dori să clarific câteva termeni frecvent utilizați în programarea orientată pe obiecte. Termenii clase, obiecte, și instanțe adesea confundă oamenii cu programarea orientată obiect. Prin urmare, este important să știi cum utilizează Swift acești termeni.
A clasă este un model sau șablon pentru un exemplu al clasei respective. Termenul "obiect" este adesea folosit pentru a se referi la o instanță a unei clase. Cu toate acestea, în Swift, clasele și structurile sunt foarte asemănătoare și, prin urmare, este mai ușor și mai puțin confuz să se folosească termenul "instanță" pentru ambele clase și structuri.
Mai devreme în această serie, am lucrat cu funcții. În contextul claselor și structurilor, ne referim de obicei la funcții ca metode. Cu alte cuvinte, metodele sunt funcții care aparțin unei anumite clase sau structuri. În contextul claselor și structurilor, puteți utiliza ambii termeni alternativ, deoarece fiecare metodă este o funcție.
Să ne umezim picioarele și să definim o clasă. Activați Xcode și creați un nou loc de joacă. Scoateți conținutul locului de joacă și adăugați următoarea definiție a clasei.
personal de clasă
clasă
cuvântul cheie indică faptul că definim o clasă numită Persoană. Punerea în aplicare a clasei este înfășurată într-o pereche de bretele curbate. Chiar dacă Persoană
clasa nu este foarte utilă în forma sa actuală, este o clasă adecvată, funcțională Swift.
Ca în majoritatea celorlalte limbi de programare orientate pe obiecte, o clasă poate avea proprietăți și metode. În exemplul actualizat de mai jos, definim trei proprietăți:
Nume
, o proprietate variabilă de tip Şir?
numele de familie
, o proprietate variabilă de tip Şir?
locul naşterii
: o proprietate constantă de tip Şir
Persoana din clasa var firstName: String? var lastName: String? let birthPlace = "Belgia"
După cum ilustrează exemplul, definirea proprietăților într-o definiție de clasă este similară cu definirea variabilelor și constantelor regulate. Noi folosim var
cuvânt cheie pentru a defini o proprietate variabilă și lăsa
cuvânt cheie pentru a defini o proprietate constantă.
Proprietățile de mai sus sunt, de asemenea, cunoscute sub numele de proprietățile stocate. Mai târziu, în această serie, învățăm despre proprietățile calculate. După cum sugerează și numele, proprietățile stocate sunt proprietăți stocate de instanța de clasă. Ele sunt similare cu proprietățile din Obiectiv-C.
Este important să rețineți că fiecare proprietate stocată trebuie să aibă o valoare după inițializare sau să fie definită ca un tip opțional. În exemplul de mai sus, dăm locul naşterii
proprietate o valoare inițială de "Belgia"
. Acest lucru îi spune lui Swift că proprietatea locului de naștere este de tip Şir
. Mai târziu, în acest articol, vom arunca o privire la inițializare în detaliu și vom explora modul în care se leagă cu proprietățile de inițializare.
Chiar dacă am definit locul naşterii
proprietatea ca o constantă, este posibil să-i schimbăm valoarea în timpul inițializării unui a Persoană
instanță. Odată ce instanța a fost inițializată, locul naşterii
proprietatea nu mai poate fi modificată, deoarece am definit proprietatea ca o proprietate constantă cu lăsa
cuvinte cheie.
Putem adăuga comportament sau funcționalitate unei clase prin funcții sau metode. În multe limbi de programare, metodă este folosit în loc de funcţie în contextul claselor și instanțelor. Definirea unei metode este aproape identică cu definirea unei funcții. În următorul exemplu, definim Numele complet()
metodă în Persoană
clasă.
Persoana din clasa var firstName: String? var lastName: String? () [] [] [] [] [] [] [] [] [ Numeînapoi] return parts.joined (separator: "")
Metoda Numele complet()
este imbricată în definiția clasei. Nu accepta parametri si returneaza a Şir
. Punerea în aplicare a directivei Numele complet()
metoda este simplă. Prin legarea opțională, pe care am discutat-o mai devreme în această serie, accesăm valorile stocate în Nume
și numele de familie
proprietăţi.
Stochează numele și prenumele Persoană
instanță într-o matrice și să se alăture părților cu un spațiu. Motivul acestei implementări oarecum ciudate ar trebui să fie evident: numele și prenumele pot fi goale, motiv pentru care ambele proprietăți sunt de tip Şir?
.
Am definit o clasă cu câteva proprietăți și o metodă. Cum creăm o instanță a Persoană
clasă? Dacă sunteți familiarizați cu Obiectiv-C, atunci veți plăcea concisitatea următorului fragment.
let john = Persoană ()
Instanțializarea unei instanțe a unei clase este foarte asemănătoare cu invocarea unei funcții. Pentru a crea o instanță, numele clasei este urmat de o pereche de paranteze, iar valoarea returnată este atribuită unei constante sau variabile.
În exemplul nostru, constanta Ioan
acum arată un exemplu al Persoană
clasă. Acest lucru înseamnă că nu putem schimba nici una din proprietățile sale? Următorul exemplu răspunde la această întrebare.
john.firstName = "John" john.lastName = "Doe" john.birthPlace = "Franța"
Putem accesa proprietățile unei instanțe utilizând comoditatea sintaxei punctuale. În exemplu, am stabilit Nume
la "Ioan"
, numele de familie
la "Căprioară"
, și locul naşterii
la "Franţa"
. Înainte de a trage concluzii bazate pe exemplul de mai sus, trebuie să verificăm orice eroare la locul de joacă.
reglaj Nume
și numele de familie
nu pare să provoace probleme. Dar atribuirea "Franţa"
la locul naşterii
proprietatea duce la o eroare. Explicația este simplă.
Chiar dacă Ioan
este declarată ca o constantă, care nu ne împiedică să modificăm Persoană
instanță. Există însă un singur avertisment: numai proprietățile variabile pot fi modificate după inițializarea unei instanțe. Proprietățile definite ca fiind constante nu pot fi modificate odată ce o valoare este atribuită.
O proprietate constantă poate fi modificată în timpul inițializării unei instanțe. In timp ce locul naşterii
proprietatea nu poate fi schimbată o dată Persoană
instanța este creată, clasa nu ar fi foarte utilă dacă am putea doar instanțiate Persoană
instanțe cu locul de naștere al "Belgiei". Să facem asta Persoană
clasa un pic mai flexibil.
Inițializarea este o fază a duratei de viață a unui exemplu de clasă sau de structură. În timpul inițializării, pregătim instanța pentru utilizare prin popularea proprietăților sale cu valorile inițiale. Inițializarea unei instanțe poate fi personalizată prin implementarea unui inițializator, un tip special de metodă. Să definim un inițializator pentru Persoană
clasă.
Persoana din clasa var firstName: String? var lastName: String? letî birthPlace = "Belgia" init () birthPlace = "Franța" ...
Am definit un inițializator, dar ne confruntăm cu mai multe probleme. Aruncați o privire la eroarea pe care compilatorul ne-o aruncă.
Initiatorul nu este doar inutil, compilatorul ne avertizeaza si ca nu putem modifica valoarea lui locul naşterii
deoarece are deja o valoare inițială. Putem rezolva eroarea eliminând valoarea inițială a locul naşterii
proprietate.
Persoana din clasa var firstName: String? var lastName: String? let birthPlace: String init () birthPlace = "Franța" ...
Rețineți că numele inițializatorului, init ()
, nu este precedată de FUNC
cuvinte cheie. Spre deosebire de inițialele din Obiectiv-C, un inițializator din Swift nu returnează instanța inițializată.
Un alt detaliu important este cum am setat locul naşterii
proprietate cu o valoare inițială. Am setat locul naşterii
proprietate folosind numele de proprietate, dar este, de asemenea, bine să fie mai explicit ca aceasta.
init () self.birthPlace = "Franța"
de sine
cuvântul cheie se referă la instanța inițializată. Aceasta înseamnă că self.birthPlace
se referă la locul naşterii
proprietatea instanței. Putem omite de sine
, ca în primul exemplu, pentru că nu există confuzie cu privire la care proprietate ne referim. Acest lucru nu este întotdeauna cazul, totuși. Permiteți-mi să vă explic ce vreau să spun.
Initializatorul pe care l-am definit nu este foarte util in momentul de fata si nu rezolva problema cu care am inceput: sa putem defini nasterea unei persoane in timpul initializarii.
În multe situații, doriți să transmiteți valorile inițiale inițializatorului pentru a personaliza instanța pe care o instanțiați. Acest lucru este posibil prin crearea unui inițializator personalizat care acceptă unul sau mai multe argumente. În exemplul următor, vom crea un inițializator personalizat care acceptă un argument, locul naşterii
, de tip Şir
.
init (birthPlace: String) self.birthPlace = birthPlace
Două lucruri merită să fie subliniate. În primul rând, trebuie să accesăm locul naşterii
prin intermediul proprietății self.birthPlace
pentru a evita ambiguitatea, deoarece numele parametrului local este egal cu locul naşterii
. În al doilea rând, chiar dacă nu am specificat un nume de parametru extern, Swift creează implicit un nume de parametru extern care este egal cu numele parametrului local.
În exemplul următor, instanțiăm un altul Persoană
instanță prin invocarea inițializatorului personalizat pe care tocmai l-am definit.
maxime = Persoana (birthPlace: "Franța") print (maxime.birthPlace)
Prin trecerea unei valori pentru locul naşterii
parametru la inițializator, putem atribui o valoare personalizată constantei locul naşterii
proprietate în timpul inițializării.
Ca și în Obiectiv-C, o clasă sau o structură poate avea mai multe inițializatoare. În următorul exemplu, creăm două Persoană
instanțe. În prima linie, folosim inițializatorul implicit. În al doilea rând, folosim inițializatorul personalizat pe care l-am definit mai devreme.
permiteți p1 = Persoană () să p2 = Persoană (birthPlace: "France")
Structurile sunt surprinzător de asemănătoare cu clasele, dar există câteva diferențe-cheie. Să începem prin definirea unei structuri de bază.
Structura portofelului var dollars: Int var cents: Int
La prima vedere, singura diferență este utilizarea struct
cuvânt cheie în loc de clasă
cuvinte cheie. Exemplul ne arată, de asemenea, o abordare alternativă de a furniza valori inițiale proprietăților. În loc să setăm o valoare inițială pentru fiecare proprietate, putem da proprietăților o valoare inițială în inițializatorul structurii. Swift nu va arunca o eroare, deoarece inspectează de asemenea inițializatorul pentru a determina valoarea inițială și tipul fiecărei proprietăți.
Puteți începe să vă întrebați ce este diferența dintre clase și structuri. La prima vedere, ele arată identice în formă și funcție, cu excepția clasă
și struct
Cuvinte cheie. Cu toate acestea, există o serie de diferențe cheie.
Clasele susțin moștenirea, în timp ce structurile nu sunt. Următorul exemplu ilustrează acest lucru. Modelul de design al moștenirii este indispensabil în programarea orientată pe obiecte și, în Swift, este o diferență esențială între clase și structuri.
Persoana din clasa var firstName: String? var lastName: String? let birthPlace: String init (birthPlace: String) self.birthPlace = birthPlace clasa Student: Persoana var school: String? permite student = Student (birthPlace: "France")
În exemplul de mai sus, Persoană
clasa este părinte sau superclasă a Student
clasă. Aceasta înseamnă că Student
clasa moștenește proprietățile și comportamentul Persoană
clasă. Ultimul rând ilustrează acest lucru. Inițializăm a Student
exemplu prin invocarea inițializatorului personalizat definit în Persoană
clasă.
Următorul concept este probabil cel mai important concept din Swift pe care îl veți învăța astăzi, diferența dintre tipuri de valori și tipuri de referință. Structurile sunt tipuri de valori, ceea ce înseamnă că ele sunt transmise prin valoare. Un exemplu ilustrează cel mai bine acest concept.
(x: 0, y: 0) var punct2 = punct (x: 0, y: 0) point1 point1.x = 10 print (punctul1.x) // 10 print (punctul2.x) // 0
Definim o structură, Punct
, pentru a încapsula datele pentru a stoca o coordonată într-un spațiu bidimensional. Instanțăm point1
cu X
egal cu 0
și y
egal cu 0
. Noi atribuim point1
la punct2
și setați X
coordonate de point1
la 10
. Dacă ieșim X
coordonate ale ambelor puncte, descoperim că nu sunt egale.
Structurile sunt transmise prin valoare, în timp ce clasele sunt transmise prin referință. Dacă intenționați să continuați să lucrați cu Swift, trebuie să înțelegeți declarația anterioară. Când ne-am desemnat point1
la punct2
, Swift a creat o copie a lui point1
și l-au alocat punct2
. Cu alte cuvinte, point1
și punct2
fiecare punct la o altă instanță a Punct
structura.
Să repetăm acum acest exercițiu cu Persoană
clasă. În exemplul următor, instanțiăm a Persoană
exemplu, setați proprietățile, atribuiți PERSON1
la PERSON2
, și actualizați Nume
proprietatea PERSON1
. Pentru a vedea ce înseamnă trecerea prin referință pentru clase, vom extrage valoarea lui Nume
proprietatea celor două Persoană
instanțe.
var person1 = persoană (birthPlace: "Belgia") person1.firstName = "Jane" person1.lastName = "Doe" var person2 = person1 person1.firstName = Janine print (person1.firstName! FirstName!) // Janine
Exemplul demonstrează că clasele sunt tipuri de referință. Aceasta înseamnă că PERSON1
și PERSON2
se referă sau se referă la același lucru Persoană
instanță. Prin atribuirea PERSON1
la PERSON2
, Swift nu creează o copie a lui PERSON1
. PERSON2
variabil puncte la acelasi Persoană
instanță PERSON1
se îndreaptă spre. Schimbarea Nume
proprietatea PERSON1
afectează de asemenea Nume
proprietatea PERSON2
, deoarece aceștia fac referire la același lucru Persoană
instanță.
Așa cum am menționat de mai multe ori în acest articol, clasele și structurile sunt foarte asemănătoare. Ceea ce separă clasele și structurile este foarte important. Dacă conceptele de mai sus nu sunt clare, atunci vă încurajez să citiți articolul încă o dată pentru a lăsa conceptele acoperite de noi.
În această tranșă de Swift From Scratch, am început să explorăm elementele de bază ale programării orientate pe obiecte în Swift. Clasele și structurile sunt elementele fundamentale ale majorității proiectelor Swift și vom afla mai multe despre ele în următoarele câteva lecții din această serie.
În următoarea lecție, continuăm să explorăm clasele și structurile examinând mai atent proprietățile și moștenirea.
Dacă doriți să aflați cum să utilizați aplicația Swift 3 pentru a codifica aplicațiile din lumea reală, consultați cursul nostru Creați aplicații iOS cu Swift 3. Indiferent dacă sunteți nou în dezvoltarea de aplicații iOS sau căutați să treceți de la obiectivul C, curs va începe cu Swift pentru dezvoltarea de aplicații.