În Swift mai este un mod de a crea tipuri de date complexe numite clase. Ele arată similar cu structurile, dar au un număr de diferențe importante, printre care:
Toate cele trei sunt diferențe mari, deci o sa le acopăr în amănunt înainte să continuăm.
Dacă am converti structura Person
într-o clasă Person
, Swift nu ne va lăsa să facem asta:
class Person {
var clothes: String
var shoes: String
}
Asta din cauză că declarăm cele două proprietăți să fie de tipul String
, ceea ce dacă îți amintești trebuie neapărat să aibă o valoare. Asta era în regulă într-o structură deoarece Swift produce un inițializator per membru în mod automat, forțându-ne să furnizăm valori pentru cele două proprietăți, dar acest lucru nu se întâmplă în mod automat cu clasele în, deci Swift nu poate fi sigur că ele vor avea valori.
Există trei soluții: fă cele două valori stringuri opționale, dă-le valori implicite, sau să scriem propriul nostru inițializator. Prima metodă este stângace deoarece introduce opționale peste tot în codul nostru unde nu trebuie să existe. A doua opțiune funcționează, dar estre puțin inutilă dacă acele valori implicite nu vor fi folosite. Ne mai rămâne ultima opțiune, și aceasta este cea corectă: să scriem propriile inițializatoare.
Pentru a face asta, crează o metodă înăuntrul clasei numită init()
care primește cei doi parametrii care ne interesează:
class Person {
var clothes: String
var shoes: String
init(clothes: String, shoes: String) {
self.clothes = clothes
self.shoes = shoes
}
}
Sunt două lucruri care se poate să-ți sară în vedere.
Primul, nu scrii cuvântul func
înaintea metodei init()
, deoarece ea este specială. Al doilea, deoarece numele parametrilor sunt aceleași cu numele proprietăților cărora vrem să le atribuim, folosești self.
pentru a te face în'eles – "proprietatea clothes
a obiectului ar trebui să fie cea a parametrului de intrare clothes
." Dacă dorești poți să le dai nume unice – depinde doar de tine.
Important: Swift arecerința ca toate valoriile non-opționale să aibă o valoare până la sfârșitul inițializatorului, sau când inițializatorul apelează oricare altă metodă – oricare va fi prima.
A doua diferență dintre clase și structuri este aceea că clasele se pot construi una pe cealaltă pentru a creea lucruri mai mare, numită și moștenire. Aceasta este o tehnică folosită intens în Cocoa Touch, chiar și în cele mai fundamentale programe, deci este ceva ce ar trebui să exersezi.
Să începem cu ceva simplu: o clasă Singer
care are ca proprietăți numele și vârsta . Cât despre metode, va fi un simplu inițializator care va seta proprietățile, plus o metodă sing()
care va produce niște cuvinte:
class Singer {
var name: String
var age: Int
init(name: String, age: Int) {
self.name = name
self.age = age
}
func sing() {
print("La la la la")
}
}
Acum putem crea o instanță a acelui obiect apelând inițializatorul, apoi îi putem citi proprietățile și apela metodele:
var taylor = Singer(name: "Taylor", age: 25)
taylor.name
taylor.age
taylor.sing()
Asta este clasa noastră de bază, dar vom construi pe ea: Vreau să definesc o clasă CountrySinger
care are tot ceea ce clasa Singer
are, dar când apelez sing()
vreau să afișeze "Trucks, guitars, and liquor" în schimb.
Ai putea, bine înteles să copiezi clasa originală Singer
și să o aplici unei noi clase CountrySinger
dar acesta este un mod leneș de a programa și se va întoarce împotriva ta când vei face modificări ulterioare clasei Singer
și vei uita să le copiezi. În loc, Swift are o soluție mai inteligentă: putem defini clasa CountrySinger
ca fiind bazată pe Singer
și va primi toate proprietățile și metodele pentru a putea construi pe ele:
class CountrySinger: Singer {
}
Cele doup punte produc magia: Înseamnă că "CountrySinger
extinde Singer
." Acum, această nouă clasă CountrySinger
(numită subclasă) nu adaugă nimic clasei Singer
(numită clasă părinte, sau superclasă) încă. Vrem ca ea să aibă propria metodă sing()
, dar în Swift trebuie să înveți un cuvânt nou: override
. Asta înseamnă "Știu că această metodă a fost implementată în clasa părinte, dar vreau să o modific pentru această subclasă."
Având cuvântul cheie override
este de ajutor, deoarece îți face intenția clară. Îi permite lui Swift să îți verifice codul: dacă nu folosești override
Swift nu te va lăsa să modifici metoda pe care ai obținut-o de la superclasă, sau dacă folosești override
și nu este nimic de suprascris, Swift îți va arăta eroarea.
Deci, trebuie să folosim override func
, așa:
class CountrySinger: Singer {
override func sing() {
print("Trucks, guitars, and liquor")
}
}
Acum modifică modul în care obiectul taylor
este creat:
var taylor = CountrySinger(name: "Taylor", age: 25)
taylor.sing()
Dacă modifici CountrySinger
în Singer
ar trebui să vezi mesajele diferite apărând în panoul cu rezultate.
Acum, pentru a complica lucrurile, vom defini o nouă clasă numită HeavyMetalSinger
. Dar de data aceasta vom stoca o nouă proprietate numită noiseLevel
definind cât de tare acest cântăreț de heavy metal țipă în microfon.
Aici apare o problemă, și este una care trebuie rezolvată într-un anumit mod:
Singer
nu are o proprietate noiseLevel
.HeavyMetalSinger
care acceptă un nivel de zgomot.name
și age
ale cântărețului de heavy metal, pentru a le putea trimite superclasei Singer
.noiseLevel
) apoi să transmitem ceilalți parametrii superclasei.Asta poate suna groaznic de complicat, însă codul este simplu. Uite clasa HeavyMetalSinger
, completă cu propria metodă sing()
:
class HeavyMetalSinger: Singer {
var noiseLevel: Int
init(name: String, age: Int, noiseLevel: Int) {
self.noiseLevel = noiseLevel
super.init(name: name, age: age)
}
override func sing() {
print("Grrrrr rargh rargh rarrrrgh!")
}
}
Observă că inițializatorul acceptă trei parametrii, apoi apelează super.init()
pentru a transmite name
și age
la superclasa Singer
- dar numai după ce propria proprietate a fost setată. Vei vedea super
folosit de multe ori în obiecte, și asta înseamnă doar "apelează o metodă din clasa moștenită.” De obicei este folosit pentru a spune "lasă clasa părinte să facă orice are nevoie să facă mai înâi, apoi voi face ce vreau eu extra."
Moștenirea este un subiect mare deci nu te necăji dacă nu este totul clas încă. Oricum, mai este un lucru pe care trebuie să-l știi: moștenirea de multe ori se petrece pe multe nivele. De exemplu, A poate moșteni pe B, și B poate moșteni pe C, și C poate moșteni pe D, și așa mai departe. Asta îți permite să construiești funcționalitate și să refolosești un număr de clase, ajutânddu-te să menții un cod modular și ușor de înțeles.
Dacă vrei ca o parte din sistemul de operare Apple să îți apeleze o metodă a unei clase Swift, trebuie să o marchezi cu un atribut special: @objc
. Înseamnă pe scurt “Objective-C”, și atributul marchează această metodă ca fiind disponibilă pentru codul Objective-C mai vechi – adică aproape tot codul iOS, macOS, watchOS, and tvOS. De exemplu, dacă îi ceri sistemului să îți apeleze metoda după o secundă, va trebui să o marchezi cu @objc
.
Nu-ți fă prea multe probleme în legătură cu @objc
pentru moment – nu doar că îți voi explica mai târziu, dar Xcode îți va spune întotdeauna când este necesar. În mod contrar, dacă nu vrei să folosești @objc
pentru anumite metode poți să pui @objcMembers
înaintea clasei pentru a face toate metodele disponibile pentru Objective-C.
Când copiezi o structură, ea este duplicată împreună cu toate valorile ei. Ceea ce înseamnă că dacă modifici o copie a unei structuri, celelalte copii vor rămâne neschimbate – toate sunt individuale. În cazul claselor, fiecare copie a unui obiect are referință la obiectul original, deci dacă vei modifica una, toate se vor modifica. Swift numește structuriile "tipuri valoare" deoarece ele referențiază doar o valoare, și clasele "tipuri referință" deoarece obiectele sunt doar referințe ale valorii reale.
Aceasta este o diferență importantă, ceea ce înseamnă că alegerea dintre structuri și clase este una importantă:
Dacă ar fi să fac un rezumat al diferenței dintre structuri și clase, aș spune asta: clasele oferă mai multă flexibilitate, iar structurile oferă mai multă siguranță. Ca și regulă de bază, ar trebui să folosești întotdeauna structuri dacă nu ai un motiv specific să folosești clase.
SAVE 50% All our books and bundles are half price for Black Friday, so you can take your Swift knowledge further without spending big! Get the Swift Power Pack to build your iOS career faster, get the Swift Platform Pack to builds apps for macOS, watchOS, and beyond, or get the Swift Plus Pack to learn advanced design patterns, testing skills, and more.
Link copied to your pasteboard.