În primul articol al acestei serii introductive despre Swift, am vorbit despre filozofia lui Swift, am aruncat o primă privire asupra sintaxei sale și am subliniat câteva diferențe cheie cu Obiectiv-C. În acest articol, continuăm să explorăm sintaxa lui Swift. De asemenea, veți afla despre opțiunile opționale și veți vedea cum funcționează gestionarea memoriei în Swift.
Dacă declarațiile sunt identice în Swift și Obiectiv-C, cu excepția a două diferențe subtile:
Acestea sunt despre singurele diferențe cu declarațiile din Obiectiv-C.
După cum am văzut în primul articol, Swift include doi operatori de gamă ... <
și ...
pentru a specifica o serie de valori. Acești doi operatori sunt operatorul de interval semi-închis si operatorul cu interval închis.
O gamă pe jumătate închisă, cum ar fi 1 ... <5
, reprezintă valorile 1, 2, 3 și 4, cu excepția 5. Un interval închis, cum ar fi 1 ... 5
, reprezintă valorile 1, 2, 3, 4 și include 5.
Pot fi folosite canale în pentru
bucle, mulțime
subscript, și chiar în intrerupator
declarații. Consultați următoarele exemple.
// pentru exemplul buclă pentru i în 1 ... <10 // iterates from 1 to 9
// exemplu subscript array lăsați someArray = ["măr", "pereche", "piersic", "pepene verde", "căpșuni"] pentru fructe în uneleArray [2 ... <4] println(fruit) // outputs: peach and watermelon
// comutare exemplu switch someInt caz 0: // face ceva cu 0 caz 1 ... <5: // do something with 1,2,3,4 case 5… 10: // do something with 5,6,7,8,9,10 default: // everything else
Comenzile de comutare sunt mai puternice în Swift decât în Obiectiv-C. În Obiectiv-C, rezultatul expresiei unei instrucțiuni switch trebuie să fie de tip integer și valorile fiecărei instrucțiuni de caz trebuie să fie o expresie constantă sau constantă. Acest lucru nu este valabil în Swift. În Swift, declarațiile de caz pot fi de orice tip, inclusiv intervalele.
În Swift, comutatorul nu are pauză
declarații și nu se încadrează în mod automat de la un caz la altul. Când scrieți o instrucțiune de comutator, trebuie să aveți grijă ca toate condițiile să fie tratate de instrucțiunile sale de caz, dacă nu faceți acest lucru va duce la o eroare de compilator. O modalitate sigură de a acoperi toate condițiile este aceea de a include a Mod implicit
declarație de caz.
Iată un exemplu de a intrerupator
declarație cu Şir
cazuri:
lăsați legumele = "piper roșu" comută legume caz "țelină": lăsați legumeleComment = "Adăugați niște stafide și faceți furnici pe un jurnal". caz "castravete", "Nasture": lăsați legumeleComment = "Asta ar face un sandwich de ceai bun". implicit: lăsați legumeleComment = "Totul are un gust bun în supă".
În declarațiile Swift, declarațiile de caz nu cad în mod implicit. Aceasta a fost o decizie deliberată de proiectare pentru a evita erorile comune. Dacă un caz specific trebuie să cadă, puteți folosi cadea prin
cuvinte cheie pentru a indica acest lucru compilatorului.
comutați cevaIntre caz 0: // face ceva cu 0 caz 1: // face ceva cu 1 caz 2: // face ceva cu 2 implicit fallthrough: // face ceva pentru orice altceva // // caz 2 va cădea la implicit caz
Nu se oprește aici. Swift adaugă alte două funcții pentru comutare, legăturile de valoare si Unde clauză. Valoarea de legare este folosită cu caz
cuvinte cheie pentru a lega o constantă cu cazul de potrivire. Clauza unde adaugă o condiție suplimentară instrucțiunii caz folosind Unde
cuvinte cheie.
Aceste două concepte sunt mai bine explicate prin exemple. Următorul bloc de coduri arată cum valoare obligatorie lucrări.
(x, 0, y): println ("pe axa x cu o valoare x a lui \ (x)") (0, let y): println ("pe axa y cu valoarea ay a lui \ (y)") let (x, y): println ("undeva la (\ (x), \ (y)
Prima declarație de caz, caz (x, 0)
, se vor potrivi cu valorile în care se află yaxis
este egal cu 0
și orice valoare pentru xaxis
, și ne legăm xaxis
la constanta X
pentru a fi utilizate în declarația de caz.
Iată un exemplu de clauză unde se află în acțiune.
lăsați legumele = "piper roșu" comutați legume caz "țelină": println ("Adăugați niște stafide și faceți furnici pe un jurnal. la \ (x) ") implicit: println (" Totul are un gust bun în supă ") // ieșiri: Sunt alergic la piper roșu
Definirea funcțiilor și a închiderilor este ușoară în Swift. Dezvoltatorii obiectiv-C le cunosc mai bine ca funcții și blocuri.
În Swift, parametrii funcției pot avea valori implicite, care amintește de limbile de scripting, cum ar fi PHP și Ruby.
Sintaxa pentru funcții este după cum urmează:
func functionName (parametrulName: Type = DefaultValue) -> returnType [...] retur returnType;
Pentru a scrie a spune buna
care are un parametru Nume
de tip Şir
și returnează a bool
când reușim, scriem următoarele:
func sayHello (nume: String) -> Bool println ("hello \ (name)"); return true; sayHello ("Lumea") // ieșire // salut Lumea
Pentru a trece o valoare implicită pentru Nume
parametru, implementarea funcției ar arăta astfel:
func sayHello (nume: String = "Lumea") -> Bool println ("hello \ (name)"); return true; sayHello () // ieșire // hello World sayHello ("mike") // output // hello mike
O caracteristică care este complet absentă în Obiectiv-C este tuple. În funcția Swift, funcțiile pot returna mai multe valori sub formă de tuple. Tupele sunt tratate ca o singură variabilă, ceea ce înseamnă că le poți trece în jurul lor ca o variabilă.
Tupele sunt foarte usor de folosit. De fapt, am lucrat deja cu tupluri în articolul precedent când am enumerat un dicționar. În următorul fragment de cod, perechea de chei / valoare este o nucă.
pentru (cheie, valoare) în uneleDictionary println ("Cheia \ (cheie) are valoarea \ (valoare)"
Cum sunt utilizate tuplurile și cum beneficiezi de acestea? Să aruncăm o privire la un alt exemplu. Să modificăm cele de mai sus spune buna
pentru a returna un boolean atunci când a reușit, precum și mesajul rezultat. Facem asta prin returnarea unei tuple, (Bool, String)
. Actualizată spune buna
funcționează astfel:
func sayHello (nume: String = "Lumea") -> (Bool, String) să salute = "hello \ (name)" retur (adevărat, salut); let (succes, salut) = sayHello () println ("sayHello a returnat succesul: \ (succes) cu salut: \ (salut)"); // output // sayHello a revenit succes: 1 cu salut: salut lume
Tupele au fost pe lista de dorințe ale multor programatori Obiectiv-C pentru o lungă perioadă de timp.
O altă caracteristică interesantă a tuplurilor este că putem numi variabilele returnate. Dacă vom revedea exemplul anterior și vom da nume variabilelor tuplei, obținem următoarele:
func sayHello (nume: String = "Lumea") -> (succes: Bool, salut: String) să salute = "hello \ (name)" return (true, greeting); let status = sayHello () println ("sayHello a returnat succesul: \ (status.success) cu salut: \ (status.greeting)"); // output // sayHello a revenit succes: 1 cu salut: salut lume
Acest lucru înseamnă că, în loc de a defini o constantă separată pentru fiecare element de returnare al unei tuple, putem accesa elementele de trupă returnate folosind notația punctată așa cum se arată în exemplul de mai sus, status.success
și status.greeting
.
Închidere în Swift sunt aceleași cu blocurile din Obiectiv-C. Acestea pot fi definite în linie, trecute ca parametru sau returnate prin funcții. Le folosim exact așa cum am folosi blocurile în Obiectiv-C.
De asemenea, definirea închiderilor este ușoară. De fapt, o funcție este un caz special de închidere. Deci, nu e de mirare că definirea unei închideri arată foarte mult ca definirea unei funcții.
Închideri sunt un tip de primă clasă, ceea ce înseamnă că pot fi transferate și returnate prin funcții la fel ca orice alt tip, cum ar fi Int
, Şir
, bool
, închiderile sunt în esență blocuri de cod care pot fi numite mai târziu și au acces la domeniul în care au fost definite.
Crearea unei închideri fără nume este la fel de simplă ca înfășurarea unui bloc de cod în bretele curbate. Parametrii și tipul de întoarcere a închiderii sunt separați de corpul închizătorului cu în
cuvinte cheie.
Să presupunem că vrem să definim o închidere care revine Adevărat
dacă un număr este egal, atunci închiderea ar putea părea ceva asemănător:
este isEven = (number: Int) -> Bool înăuntă mod = numărul% 2 return (mod == 0)
este chiar
închiderea durează un an Int
ca parametru unic și returnează a bool
. Tipul acestei închideri este (numărul: Int) -> Bool
, sau (Int -> Bool)
pe scurt. Putem suna este chiar
oriunde în codul nostru, așa cum am invoca un bloc de cod în Obiectiv-C.
Pentru a trece o închidere de acest tip ca parametru al unei funcții, folosim tipul de închidere în definiția funcției:
este isEven = (number: Int) -> Bool in let mod = numărul% 2; retur (mod == 0); func verificIfEven (număr: Int, verificator: (Int-> Bool)) -> Bool return verificator (număr); verifyIfEven (12, esteEven); // returnează adevărat checkIfEven (19, isEven); // returnează false
În exemplul de mai sus, verificator
parametru al verifyIfEven
funcția este o închidere pe care o trecem la funcție.
Este timpul să vorbim despre piatra de temelie a programelor orientate pe obiecte, clase. Clasele, așa cum au fost menționate mai sus, sunt definite într - un singur fișier de implementare cu un .rapid extensie. Declarațiile și metodele de proprietate sunt definite în fișierul respectiv.
Creați o clasă cu clasă
cuvânt cheie urmat de numele clasei. Implementarea clasei este înfășurată într-o pereche de bretele curbate. Ca și în Obiectiv-C, convenția de numire pentru clase este de a folosi cazul cămășii superioare pentru numele de clasă.
hotel clasa // proprietăți // funcții
Pentru a crea o instanță a Hotel
clasa scrie:
h h = Hotel ()
În Swift, nu este nevoie să sunați init
pe obiecte ca init
se numește automat pentru noi.
Clasa de moștenire urmează același model ca și în Obiectiv-C, un colon separă numele clasei și cel al superclasei. În exemplul următor, Hotel
moșteneste de la BigHotel
clasă.
clasa BigHotel: Hotel
Ca și în Obiectiv-C, folosim notația punctului pentru a accesa proprietățile obiectului. Cu toate acestea, Swift utilizează notația punctului pentru a invoca metodele de clasă și instanță, după cum puteți vedea mai jos.
// Obiectiv-C UIView * vizualizare = [[UIView alloc] init]; [self.view addSubview: vizualizare]; / / Swift permite vizualizarea = UIView () self.view.addSubview (vizualizare)
O altă diferență cu obiectivul C este că Swift nu distinge între variabilele de instanță (ivars) și proprietățile. O variabilă de instanță este o proprietate.
Declararea unei proprietăți este la fel ca definirea unei variabile sau a unei constante, folosind var
și lăsa
Cuvinte cheie. Singura diferență este contextul în care acestea sunt definite, adică contextul unei clase.
class Hotel săli camere = 10 var fullRooms = 0
În exemplul de mai sus, camere
este o valoare imuabilă, o constantă 10
și fullRooms
este o variabilă cu o valoare inițială de 0
, pe care le putem schimba mai târziu. Regula este că proprietățile trebuie inițializate atunci când sunt declarate. Singura excepție de la această regulă sunt opțiunile, pe care le vom discuta într-un moment.
Limbajul Swift definește și proprietățile calculate. Proprietățile computerizate nu sunt nimic mai mult decât getters și setteri fantezie care nu stochează o valoare. După cum indică și numele, acestea sunt calculate sau evaluate în zbor.
Mai jos este un exemplu de proprietate calculată. Am schimbat-o camere
proprietate la var
pentru restul acestor exemple. Veți afla de ce mai târziu.
hotel clasa var camere = 10 var fullRooms = 0 var descriere: String get return Dimensiune hotel: \ (camere) capacitati camere: \ (fullRooms) / \ (camere) "
Deoarece Descriere
proprietatea este doar pentru citire și are doar întoarcere
declarație, putem omite obține
cuvânt cheie și acolade bretele, și să păstreze numai întoarcere
afirmație. Aceasta este o stenogramă și asta voi folosi în restul acestui tutorial.
hotel clasa var camere = 10 var fullRooms = 0 var descriere: String return "Dimensiune hotel: \ (camere) capacitati camere: \ (fullRooms) / \ (camere)"
De asemenea, putem defini proprietăți computerizate citire-scriere. In clasa noastra Hotel
, vrem un an emptyRooms
proprietate care primește numărul de camere goale în hotel, dar dorim și să ne actualizăm fullRooms
când am setat emptyRooms
proprietate calculată. Putem face acest lucru folosind a stabilit
după cum se arată mai jos.
hotel clasa var camere = 10 var fullRooms = 0 var descriere: String return "Dimensiune hotel: \ (camere) capacitati camere: \ (fullRooms) / \ (rooms)" var emptyRooms: fullRooms set // constantă newValue este disponibilă aici // care conține valoarea transmisă dacă (newValue < rooms) fullRooms = rooms - newValue else fullRooms = rooms let h = Hotel() h.emptyRooms = 3 h.description // Size of Hotel: 10 rooms capacity:7/10
În emptyRooms
setter, newValue
constanta ne este predata si reprezinta valoarea transferata catre setter. De asemenea, este important să rețineți că proprietățile calculate sunt întotdeauna declarate ca variabile, folosind var
cuvânt cheie, deoarece valoarea lor calculată se poate schimba.
Am acoperit deja funcțiile din acest articol. Metodele nu sunt altceva decât funcții care sunt legate de un tip, cum ar fi o clasă. În următorul exemplu vom implementa o metodă instanță, bookNumberOfRooms
, în Hotel
pe care am creat-o mai devreme.
hotel clasa var camere = 10 var fullRooms = 0 var descriere: String return "Dimensiune hotel: \ (camere) capacitati camere: \ (fullRooms) / \ (rooms)" var emptyRooms: fullRooms set // constantă newValue este disponibilă aici // care conține valoarea transmisă dacă (newValue < rooms) fullRooms = rooms - newValue else fullRooms = rooms func bookNumberOfRooms(room:Int = 1) -> Bool if (self.emptyRooms> room) auto.fullRooms ++; return true else return false h = hotel () h.emptyRooms = 7 h.description // Dimensiune hotel: 10 camere capacitate: 3/10 h.bookNumberOfRooms (cameră: 2) .description // Dimensiune hotel: 10 camere capacitate: 5/10 h.bookNumberOfRoom () // returneaza descrierea adevarata // Dimensiune hotel: 10 camere capacitate: 6/10
Initializatorul implicit pentru clase este init
. În init
, setăm valorile inițiale ale instanței create.
De exemplu, dacă am avea nevoie de a Hotel
subclasa cu 100 de camere, atunci am avea nevoie de un inițializator pentru a seta camere
proprietate la 100
. Amintiți-vă că am schimbat anterior camere
de la a fi o constantă a fi o variabilă în Hotel
clasă. Motivul este că nu putem schimba constantele moștenite într-o subclasă, doar variabilele moștenite pot fi schimbate.
clasa BigHotel: Hotel init () super.init () camere = 100 bh = BigHotel () println (bh.description); // Dimensiune hotel: 100 camere capacitate: 0/100
Inițializatorii pot lua, de asemenea, parametri. Următorul exemplu vă arată cum funcționează acest lucru.
clasa CustomHotel: Hotel init (dimensiune: Int) super.init () camere = dimensiune c = CustomHotel (dimensiune: 20) c.description // Dimensiune hotel: 20 camere capacitate: 0/20
Acesta este unul dintre cele mai tari lucruri din Swift. În Swift, o subclasă poate suprascrie atât metodele, cât și proprietățile calculate. Pentru a face acest lucru, folosim trece peste
cuvinte cheie. Hai să ignorăm Descriere
proprietate calculată în CustomHotel
clasă:
clasa CustomHotel: Hotel init (dimensiune: int) super.init () camere = dimensiune suprascriere var descriere: String return super.description + "Howdy!" c = CustomHotel (dimensiune: 20) c.description // Dimensiune hotel: 20 camere capacitate: 0/20!
Rezultatul este că Descriere
returnează rezultatul superclass Descriere
cu șirul "Salutare!"
anexat la acesta.
Ce este cool despre metodele imperative și proprietățile calculate este trece peste
cuvinte cheie. Când compilatorul vede trece peste
cuvântul cheie, verifică dacă superclama clasei implementează metoda care este suprascrisă. Compilatorul verifică, de asemenea, dacă proprietățile și metodele unei clase sunt în conflict cu proprietățile sau metodele de mai sus în arborele de mostenire.
Nu știu de câte ori o tipografie într-o metodă suprascrisă în Obiectiv-C ma făcut să blestem, pentru că codul nu funcționa. În Swift, compilatorul vă va spune exact ce este în neregulă în aceste situații.
Structuri, definite cu struct
, sunt mai puternice în Swift decât în C și Obiectiv-C. În C, structura definește numai valori și indicatori. Structurile Swift sunt la fel ca structurile C, dar ele sprijină, de asemenea, proprietățile și metodele computerizate.
Orice puteți face cu o clasă, puteți face o structură, cu două diferențe importante:
Iată câteva exemple de structuri în Swift:
struct Rect var orig: Punct var dimensiune: Dimensiune var area: Dublu return size.width * size.height func esteBiggerThanRect (r: Rect) -> Bool return (self.area> r.area) var x = 0 var y = 0 struct Dimensiunea var width = 0 var height = 0
Opțiunile sunt un concept nou dacă vin din Obiectiv-C. Ei rezolvă o problemă cu care ne confruntăm toți ca programatori. Când accesăm o variabilă a cărei valoare nu suntem siguri, returnăm de obicei un indicator, cunoscut ca un santinel, pentru a indica faptul că valoarea returnată este o valoare fără valoare. Permiteți-mi să ilustrez acest lucru cu un exemplu din obiectivul C:
NSString * someString = @ "ABCDEF"; NSInteger pos = [someString rangeOfString: @ "B"] locație; // pos = 1
În exemplul de mai sus, încercăm să găsim poziția @ "B"
în someString
. Dacă @ "B"
se găsește, locația sau poziția sa este stocată în pos
. Dar ce se întâmplă dacă @ "B"
nu este găsit în someString
?
Documentația menționează că rangeOfString:
returnează un NSRange
cu Locație
setați la NSNotFound
constant. În cazul în care rangeOfString:
, Sentinelul este NSNotFound
. Sentinele sunt folosite pentru a indica faptul că valoarea returnată nu este validă.
În Cocoa, există multe utilizări ale acestui concept, dar valoarea santinelă diferă de context în context, 0
, -1
, NUL
, NSIntegerMax
, INT_MAX
, Zero
, etc. Problema pentru programator este că ea trebuie să-și amintească ce sentinel este folosit în ce context. Dacă programatorul nu este atent, poate gresi o valoare validă pentru un santinel și invers. Swift rezolvă această problemă cu opțiunile opționale. Pentru a cita Brian Lanier "Opționalii sunt santinelul pentru a le conduce pe toți".
Opțiunile au două stări, a zero
stat, ceea ce înseamnă că opțiunea nu conține nici o valoare, și o a doua stare, ceea ce înseamnă că ea deține o valoare validă. Gândiți-vă la opțiuni ca un pachet cu un indicator care să vă spună dacă conținutul pachetului este valabil sau nu.
Toate tipurile din Swift pot deveni opționale. Definim un opțional prin adăugarea unui a ?
dupa declaratia de tip asa:
hai să intrăm: Int? // someInt == zero
Atribuiți o valoare pachetului opțional la fel cum facem cu constantele și variabilele.
someInt = 10 // someInt! == 10
Amintiți-vă că opțiunile sunt asemănătoare pachetelor. Când am declarat lăsați-l pe el: Int?
, am definit o cutie goală cu o valoare de zero
. Prin atribuirea valorii 10
la caseta opțională, caseta conține un număr întreg egal cu 10
și indicatorul său sau starea devine nu zero.
Pentru a ajunge la conținutul unui opțional folosim !
operator. Trebuie să fim siguri că opțiunea are o valoare validă înainte de ao despacheta. Dacă nu faceți acest lucru, va apărea o eroare de execuție. Acesta este modul în care accesăm valoarea stocată într-o opțiune:
dacă someInt! = nil) println ("someInt: \ (someInt!)") altfel println ("someInt nu are valoare") // someInt:
Modelul de mai sus este atât de comun în Swift, încât putem simplifica blocul de cod de mai sus folosind legare opțională cu dacă lăsați
Cuvinte cheie. Uitați-vă la blocul de cod actualizat de mai jos.
dacă valoarea = someInt println ("someInt: \ (value)") altceva println ("someInt nu are valoare")
Opțiunile sunt singurele tipuri care pot dura zero
valoare. Constantele și variabilele nu pot fi inițializate sau setate la zero
. Aceasta face parte din politica de siguranță a Swift, toate variabilele și constantele non-opționale trebuie sa au o valoare.
Dacă vă aduceți aminte, înapoi când ARC a fost introdus, noi folosim puternic
și slab
cuvinte cheie pentru a defini proprietatea obiectului. Swift are, de asemenea, a puternic
și slab
modelul de proprietate, dar introduce și unul nou, unowned
. Să aruncăm o privire asupra fiecărui model de proprietate asupra obiectelor din Swift.
puternic
Referințele puternice sunt implicit în Swift. De cele mai multe ori, deținem obiectul pe care îl referăm și suntem cei responsabili pentru menținerea obiectului referit în viață.
Deoarece referințele puternice sunt implicite, nu este necesar să păstrați în mod explicit o referință puternică la un obiect, orice referință este o referință puternică.
slab
O referință slabă în Swift indică faptul că referința indică un obiect că nu suntem responsabili pentru păstrarea vieții. Este folosit în principal între două obiecte care nu au nevoie de cealaltă pentru a fi în jur pentru ca obiectul să-și continue ciclul de viață.
Există unul dar, in orice caz. În Swift, referințele slabe trebuie să fie întotdeauna variabile cu un tip opțional, deoarece acestea sunt setate la zero
când obiectul referit este dealocat. slab
cuvântul cheie este folosit pentru a declara o variabilă ca slabă:
slab var vizual: UIView?
unowned
Referințele neavizate sunt noi pentru programatorii Obiectiv-C. O referință necunoscută înseamnă că nu suntem responsabili pentru păstrarea în viață a obiectului referit, la fel ca trimiterile slabe.
Diferența cu o referință slabă este că o referință necotate nu este setată la zero
când obiectul pe care îl trimite este dealocat. O altă diferență importantă, cu referințe slabe, este că referințele necotate sunt definite ca un tip non-opțional.
Referințele neavizate pot fi constante. Un obiect neînvecinat nu există fără proprietarul său și, prin urmare, referința neamenajată nu este niciodată zero
. Referințele nefiind necesare unowned
înainte de definirea variabilei sau a constantei.
unowned var vedere: UIView
Swift este un limbaj uimitor care are o mulțime de profunzime și potențial. Este distractiv să scriem programe și elimină o mulțime de codul de boilerplate pe care îl scriem în Obiectiv-C pentru a ne asigura că codul nostru este sigur.
Vă recomandăm limba limbajului de programare Swift, care este disponibil gratuit în magazinul iBooks al Apple.