Ghid pentru dezvoltatori iOS: de la Objective-C la Learning Swift
Publicat: 2022-03-11În 2008, Apple a anunțat și a lansat iPhone SDK 2.0. Acest eveniment a început o altă revoluție în dezvoltarea de software și s-a născut o nouă generație de dezvoltatori. Acum sunt recunoscuți ca dezvoltatori iOS.
Mulți dintre acești dezvoltatori nu mai folosiseră niciodată Objective-C și aceasta a fost prima provocare pe care Apple le-a aruncat-o. În ciuda sintaxei nefamiliare și a gestionării manuale a memoriei, a avut un succes imens, ajutând la popularea App Store cu zeci de mii de aplicații. Apple a îmbunătățit continuu Objective-C cu fiecare lansare, adăugând blocuri și literale, gestionarea simplificată a memoriei cu numărare automată a referințelor și multe alte caracteristici care indică un limbaj de programare modern.
Și după 6 ani de îmbunătățire și de lucru la Objective-C, Apple a decis să arunce o altă provocare dezvoltatorilor. Încă o dată, dezvoltatorii iOS vor trebui să învețe un nou limbaj de programare: Swift . Swift elimină gestionarea nesigură a pointerului și introduce noi funcții puternice, menținând în același timp interacțiunea atât cu Objective-C, cât și cu C.
Swift 1.0 este deja o platformă de dezvoltare stabilă și puternică, care cu siguranță va evolua în moduri interesante în următorii ani. Este un moment perfect pentru a începe explorarea acestui nou limbaj, deoarece este evident viitorul dezvoltării iOS.
Scopul acestui tutorial este de a oferi dezvoltatorilor Objective-C o privire de ansamblu asupra noilor funcții ale limbajului Swift, ajutându-vă să faceți pasul următor și să începeți să adoptați Swift în munca de zi cu zi. Nu voi petrece prea mult timp explicând Objective-C și voi presupune că sunteți familiarizat cu dezvoltarea iOS.
Încercarea Swift vs. Objective-C
Pentru a începe să explorați Swift, tot ce trebuie să faceți este să descărcați XCode din App Store și să creați un loc de joacă pentru a experimenta. Toate exemplele menționate în acest articol sunt realizate astfel.
Pagina de pornire Swift a Apple este cea mai bună referință pentru a învăța programarea Swift. Veți găsi că este de neprețuit și, până când veți fi pe deplin la curent cu dezvoltarea Swift, cred că vă veți întoarce des aici.
Variabile și constante
Declararea unei variabile în Swift se face folosind cuvântul cheie var
.
var x = 1 var s = "Hello"
Veți observa că două variabile x
și s
sunt de tipuri diferite. x
este un număr întreg, în timp ce s
este un șir. Swift este un tip de limbaj sigur și va deduce tipuri variabile din valoarea atribuită. Dacă doriți să faceți codul mai lizibil, puteți adnota opțional tipul variabilei:
var y: Int y = 2
Constanțele sunt similare, dar le declarați folosind let
în loc de var
. Valoarea unei constante nu trebuie să fie cunoscută în momentul compilării, dar trebuie să îi atribui o valoare exact o dată.
let c1 = 1 // Constant known at compile time var v = arc4random() let c2 = v // Constant known only at run time
După cum sugerează și numele, ele sunt imuabile, așa că următorul cod va provoca o eroare de compilare.
let c = 1 c = 3 // error
Alte tipuri pot fi, de asemenea, declarate constante. De exemplu, următorul cod declară o matrice ca constantă, iar dacă încercați să modificați oricare dintre elemente, compilatorul Swift va raporta o eroare:
var arr2 = [4, 5, 6] arr2[0] = 8 print (arr2) // [8, 5, 6] let arr = [1, 2, 3] a[0] = 5 // error
Opționale
Constantele trebuie inițializate la declararea lor, iar variabilele trebuie inițializate înainte de utilizare. Deci, unde este echivalentul nil
al Objective-C? Swift introduce valori opționale . Valorile opționale pot avea o valoare sau pot fi nil
. Dacă aruncați o privire la următorul cod, veți observa că lui x
i s-a atribuit o valoare Optional
de 2014
. Aceasta înseamnă că compilatorul Swift era conștient de faptul că x
ar putea fi, de asemenea, nil
.
var s = "2014" var x = s.toInt() print(x) // Optional(2014)
Dacă faceți o modificare în acest cod și atribuiți valoarea "abc"
lui s
, care nu poate fi convertit într-un număr întreg, veți observa că x
este acum un nil
.
var s = "abc" var x = s.toInt() print(x) // nil
Tipul de returnare al toInt()
este Int?
, care este opțional Int . Să încercăm să apelăm o funcție standard pe x
:
var x = "2014".toInt() print(x.successor()) // error
Compilatorul semnalează o eroare, deoarece x
este opțional și ar putea fi nul . Mai întâi trebuie să testăm x
și să ne asigurăm că funcția successor
este invocată pe un număr real și nu pe o valoare nil
:
var x = "2014".toInt() if x != nil { print(x!.successor()) // 2015 }
Rețineți că trebuie să despachetăm x
adăugând un semn de exclamare (!) . Când suntem siguri că x
conține o valoare, o putem accesa. În caz contrar, vom primi o eroare de rulare. De asemenea, putem face ceea ce Swift numește legare opțională , transformând opționalul într-o variabilă non-opțională
let x = "123".toInt() if let y = x { print(y) }
Codul din instrucțiunea if
se va executa numai dacă x
are o valoare și o va atribui lui y
. Rețineți că nu trebuie să despachetăm y
, tipul său nu este opțional, deoarece știm că x
nu este nil
.
Consultați tutorialul Swift de la Apple pentru a citi mai multe detalii despre opționale și caracteristici frumoase, cum ar fi înlănțuirea opțională
Interpolarea șirurilor
În Objective-C, formatarea șirurilor se face de obicei cu metoda stringWithFormat:
::
NSString *user = @"Gabriel"; int days = 3; NSString *s = [NSString stringWithFormat:@"posted by %@ (%d days ago)", user, days];
Swift are o caracteristică numită interpolare șiruri pentru a face același lucru, dar este mai compact și mai ușor de citit:
let user = "Gabriel" let days = 3 let s = "posted by \(user) \(days) ago"
Puteți folosi și expresii:
let width = 2 let height = 3 let s = "Area for square with sides \(width) and \(height) is \(width*height)"
Pentru a afla mai multe despre interpolarea șirurilor Swift și alte funcții noi, accesați aici.
Funcții
Definiția funcției în Swift este diferită de C. Un exemplu de definiție a funcției este mai jos:
func someFunction(s:String, i: Int) -> Bool { ... // code }
Funcțiile Swift sunt tipuri de primă clasă . Aceasta înseamnă că puteți atribui funcții variabilelor, le puteți transmite ca parametri altor funcții sau le puteți face să returneze tipuri:
func stringLength(s:String) -> Int { return countElements(s) } func stringValue(s:String) -> Int { if let x = s.toInt() { return x } return 0 } func doSomething(f:String -> Int, s:String) -> Int { return f(s).successor() } let f1 = stringLength let f2 = stringValue doSomething(f1, "123") // 4 doSomething(f2, "123") // 124
Din nou, Swift deduce tipurile de f1
și f2
( String
-> Int
), deși le-am fi putut defini explicit:
let f1:String -> Int = stringLength
Funcțiile pot returna și alte funcții:
func compareGreaterThan(a: Int, b: Int) -> Bool { return a > b } func compareLessThan(a: Int, b: Int) -> Bool { return a < b } func comparator(greaterThan:Bool) -> (Int, Int) -> Bool { if greaterThan { return compareGreaterThan } else { return compareLessThan } } let f = comparator(true) println(f(5, 9))
Un ghid al funcțiilor din Swift poate fi găsit aici.
Enumerări
Enumerările în Swift sunt mult mai puternice decât în Objective-C. Ca structuri Swift, ele pot avea metode și sunt transmise după valoare:
enum MobileDevice : String { case iPhone = "iPhone", Andro, WP8 = "Windows Phone8", BB = "BlackBerry" func name() -> String { return self.toRaw() } } let m = MobileDevice.Android print(m.name()) // "Android"
Spre deosebire de Objective-C, enumerările Swift pot atribui șiruri, caractere sau floats ca valori pentru fiecare membru, în afară de numere întregi. Metoda convenabilă toRaw()
returnează valoarea atribuită fiecărui membru.
Enumerările pot fi, de asemenea, parametrizate:
enum Location { case Address(street:String, city:String) case LatLon(lat:Float, lon:Float) func description() -> String { switch self { case let .Address(street, city): return street + ", " + city case let .LatLon(lat, lon): return "(\(lat), \(lon))" } } } let loc1 = Location.Address(street: "2070 Fell St", city: "San Francisco") let loc2 = Location.LatLon(lat: 23.117, lon: 45.899) print(loc1.description()) // "2070 Fell St, San Francisco" print(loc2.description()) // "(23.117, 45.988)"
Mai multe informații despre enumerari sunt disponibile aici.

Tupluri
Tuplurile grupează mai multe valori într-o singură valoare compusă. Valorile dintr-un tuplu pot fi de orice tip și nu trebuie să fie de același tip între ele.
let person = ("Gabriel", "Kirkpatrick") print(person.0) // Gabriel
De asemenea, puteți numi elementele tuplu individuale:
let person = (first: "Gabriel", last: "Kirkpatrick") print(person.first)
Tuplurile sunt extrem de convenabile ca tipuri de returnare pentru funcțiile care trebuie să returneze mai multe valori:
func intDivision(a: Int, b: Int) -> (quotient: Int, remainder: Int) { return (a/b, a%b) } print(intDivision(11, 3)) // (3, 2) let result = intDivision(15, 4) print(result.remainder) // 3
Spre deosebire de Objective-C, Swift acceptă potrivirea modelelor într-o declarație switch:
let complex = (2.0, 1.1) // real and imaginary parts switch complex { case (0, 0): println("Number is zero") case (_, 0): println("Number is real") default: println("Number is imaginary") }
În al doilea caz, nu ne pasă de partea reală a numărului, așa că folosim un _
pentru a potrivi orice. De asemenea, puteți verifica condiții suplimentare în fiecare caz. Pentru asta trebuie să legăm valorile modelului la constante:
let complex = (2.0, 1.1) switch complex { case (0, 0): println("Number is zero") case (let a, 0) where a > 0: println("Number is real and positive") case (let a, 0) where a < 0: println("Number is real and negative") case (0, let b) where b != 0: println("Number has only imaginary part") case let (a, b): println("Number is imaginary with distance \(a*a + b*b)") }
Observați cum trebuie să legăm numai valorile pe care le vom folosi în comparație sau în declarația case.
Pentru a citi mai multe despre tupluri, accesați aici.
Clase și Structuri
Spre deosebire de Objective-C, Swift nu necesită să creați interfețe separate și fișiere de implementare pentru clase și structuri personalizate. Pe măsură ce învățați Swift, veți învăța să definiți o clasă sau o structură într-un singur fișier, iar interfața externă cu acea clasă sau structură este pusă automat la dispoziție pentru utilizarea altor coduri.
Definirea claselor
Definițiile clasei sunt foarte simple:
class Bottle { var volume: Int = 1000 func description() -> String { return "This bottle has \(volume) ml" } } let b = Bottle() print(b.description())
După cum puteți vedea, declarația și implementarea sunt în același fișier . Swift nu mai folosește fișiere de antet și de implementare. Să adăugăm o etichetă exemplului nostru:
class Bottle { var volume: Int = 1000 var label:String func description() -> String { return "This bottle of \(label) has \(volume) ml" } }
Compilatorul se va plânge deoarece eticheta este o variabilă non-opțională și nu va păstra o valoare atunci când o sticlă este instanțiată. Trebuie să adăugăm un inițializator:
class Bottle { var volume: Int = 1000 var label:String init(label:String) { self.label = label } func description() -> String { return "This bottle of \(label) has \(volume) ml" } }
Sau, am putea folosi tipul Optional
pentru o proprietate, care nu trebuie inițializată. În exemplul următor, am făcut din volume
un Optional Integer
:
class Bottle { var volume: Int? var label:String init(label:String) { self.label = label } func description() -> String { if self.volume != nil { return "This bottle of \(label) has \(volume!) ml" } else { return "A bootle of \(label)" } } }
Structuri
Limbajul Swift are, de asemenea, structs
, dar sunt mult mai flexibile decât în Objective-C. Următorul tutorial de cod definește o struct
:
struct Seat { var row: Int var letter:String init (row: Int, letter:String) { self.row = row self.letter = letter } func description() -> String { return "\(row)-\(letter)" } }
La fel ca clasele din Swift, structurile pot avea metode, proprietăți, inițializatori și pot fi conforme cu protocoalele. Principala diferență dintre clase și structuri este că clasele sunt transmise prin referință, în timp ce structurile sunt transmise prin valoare .
Acest exemplu demonstrează trecerea claselor prin referință:
let b = Bottle() print(b.description()) // "b" bottle has 1000 ml var b2 = b b.volume = 750 print(b2.description()) // "b" and "b2" bottles have 750 ml
Dacă încercăm un caz similar cu struct
, veți observa că variabilele sunt transmise după valoare:
var s1 = Seat(row: 14, letter:"A") var s2 = s1 s1.letter = "B" print(s1.description()) // 14-B print(s2.description()) // 14-A
Când ar trebui să folosim struct
și când ar trebui să folosim class
? Ca și în Objective-C și C, utilizați structuri atunci când trebuie să grupați câteva valori și așteptați-vă să fie copiate mai degrabă decât referite. De exemplu, numere complexe, puncte 2D sau 3D sau culori RGB.
O instanță a unei clase este cunoscută în mod tradițional ca obiect. Cu toate acestea, clasele și structurile Swift sunt mult mai apropiate ca funcționalitate decât în alte limbi și multă funcționalitate se poate aplica instanțelor fie ale unei clase, fie ale unui tip de structură. Din acest motiv, termenul mai general folosit în referința Swift este instance
, care se aplică oricăreia dintre aceste două.
Aflați elementele de bază ale claselor și structurilor Swift aici.
Proprietăți
După cum am văzut mai devreme, proprietățile din Swift sunt declarate cu cuvântul cheie var
în interiorul unei definiții de clasă sau struct. De asemenea, putem declara constante cu o instrucțiune let
.
struct FixedPointNumber { var digits: Int let decimals: Int } var n = FixedPointNumber(digits: 12345, decimals: 2) n.digits = 4567 // ok n.decimals = 3 // error, decimals is a constant
De asemenea, rețineți că proprietățile clasei sunt puternic referite, cu excepția cazului în care le prefixați cu cuvântul cheie weak
. Cu toate acestea, există unele subtilități cu proprietăți slabe non-opționale, așa că citiți capitolul de numărare automată a referințelor din ghidul Apple Swift.
Proprietăți calculate
Proprietățile calculate nu stochează de fapt o valoare. În schimb, ele oferă un getter și un setter opțional pentru a prelua și a seta indirect alte proprietăți și valori.
Următorul cod oferă un eșantion de sign
de valoare calculată:
enum Sign { case Positive case Negative } struct SomeNumber { var number:Int var sign:Sign { get { if number < 0 { return Sign.Negative } else { return Sign.Positive } } set (newSign) { if (newSign == Sign.Negative) { self.number = -abs(self.number) } else { self.number = abs(self.number) } } } }
De asemenea, putem defini proprietăți numai pentru citire prin implementarea unui getter:
struct SomeNumber { var number:Int var isEven:Bool { get { return number % 2 == 0 } } }
În Objective-C, proprietățile sunt de obicei susținute de o variabilă de instanță, declarată explicit sau creată automat de compilator. În Swift, pe de altă parte, o proprietate nu are o variabilă de instanță corespunzătoare . Adică, magazinul de suport al unei proprietăți nu poate fi accesat direct. Să presupunem că avem acest lucru în Obiectivul-C
// .h @interface OnlyInitialString : NSObject @property(strong) NSString *string; @end // .m @implementation OnlyInitialString - (void)setString:(NSString *newString) { if (newString.length > 0) { _string = [newString substringToIndex:1]; } else { _string = @""; } } @end
Deoarece, în Swift, proprietățile calculate nu au un depozit de suport, trebuie să facem ceva de genul acesta:
class OnlyInitialString { var initial:String = "" var string:String { set (newString) { if countElements(newString) > 0 { self.initial = newString.substringToIndex(advance(newString.startIndex, 1)) } else { self.initial = "" } } get { return self.initial } } }
Proprietățile sunt explicate mai detaliat aici
Va urma
Există multe lucruri noi și mai importante despre care să învățați în Swift, cum ar fi Generics, interacțiunea cu bibliotecile Objective-C, închideri, înlănțuire opțională și supraîncărcarea operatorului. Un singur tutorial nu poate descrie în detaliu un nou limbaj, dar nu mă îndoiesc că se vor scrie multe despre învățarea programarii Swift. Cu toate acestea, cred că această lectură rapidă îi va ajuta pe mulți dezvoltatori Objective-C, care nu au reușit să găsească timp și să învețe detalii despre limbajul Swift, să se îndrepte și să-l lase pe pasărea Swift să-i ducă la noi culmi.