Swift From Scratch Introducere în clase și structuri

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

1. Introducere

Î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.

2. Terminologie

Î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.

Obiecte și instanțe

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.

Metode și funcții

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.

3. Definirea unei clase

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.

Proprietăți

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.

metode

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?.

instanţiere

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

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.

Parametrii

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.

Inițializatori multipli

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")

4. Definirea unei structuri

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.

5. Clasele și structurile

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.

Moştenire

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ă.

Copierea și referirea

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.

Concluzie

Î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. 

 


Cod