Una guida per sviluppatori iOS: da Objective-C a Learning Swift
Pubblicato: 2022-03-11Nel 2008 Apple ha annunciato e rilasciato l'iPhone SDK 2.0. Questo evento ha avviato un'altra rivoluzione nello sviluppo del software ed è nata una nuova generazione di sviluppatori. Ora sono riconosciuti come sviluppatori iOS.
Molti di questi sviluppatori non avevano mai utilizzato Objective-C prima, e questa è stata la prima sfida che Apple ha lanciato loro. Nonostante la sintassi sconosciuta e la gestione manuale della memoria, ha avuto un immenso successo, aiutando a popolare l'App Store con decine di migliaia di app. Apple ha continuamente migliorato Objective-C con ogni versione, aggiungendo blocchi e valori letterali, semplificando la gestione della memoria con il conteggio automatico dei riferimenti e molte altre funzionalità indicative di un moderno linguaggio di programmazione.
E dopo 6 anni di miglioramento e lavoro su Objective-C, Apple ha deciso di lanciare un'altra sfida agli sviluppatori. Ancora una volta, gli sviluppatori iOS dovranno imparare un nuovo linguaggio di programmazione: Swift . Swift rimuove la gestione del puntatore non sicura e introduce nuove potenti funzionalità, mantenendo l'interazione sia con Objective-C che con C.
Swift 1.0 è già una piattaforma di sviluppo stabile e solida, che sicuramente si evolverà in modi interessanti nei prossimi anni. È un momento perfetto per iniziare a esplorare questo nuovo linguaggio poiché è ovviamente il futuro dello sviluppo di iOS.
Lo scopo di questo tutorial è fornire agli sviluppatori Objective-C una rapida panoramica delle nuove funzionalità del linguaggio Swift, aiutandoti a fare il passo successivo e iniziare ad adottare Swift nel tuo lavoro quotidiano. Non passerò troppo tempo a spiegare Objective-C e presumo che tu abbia familiarità con lo sviluppo di iOS.
Provare Swift vs. Objective-C
Per iniziare a esplorare Swift tutto ciò che devi fare è scaricare XCode dall'App Store e creare un playground per sperimentare. Tutti gli esempi citati in questo articolo vengono eseguiti in questo modo.
La homepage Swift di Apple è il miglior riferimento per l'apprendimento della programmazione Swift. Lo troverai inestimabile e, finché non sarai completamente al passo con lo sviluppo di Swift, credo che tornerai spesso qui.
Variabili e costanti
La dichiarazione di una variabile in Swift viene eseguita utilizzando la parola chiave var
.
var x = 1 var s = "Hello"
Noterai che due variabili x
e s
sono di tipo diverso. x
è un numero intero, mentre s
è una stringa. Swift è un linguaggio sicuro dai tipi e dedurrà i tipi di variabili dal valore assegnato. Se desideri rendere il tuo codice più leggibile, puoi opzionalmente annotare il tipo della variabile:
var y: Int y = 2
Le costanti sono simili, ma le dichiari usando let
invece di var
. Non è necessario che il valore di una costante sia noto in fase di compilazione, ma è necessario assegnargli un valore esattamente una volta.
let c1 = 1 // Constant known at compile time var v = arc4random() let c2 = v // Constant known only at run time
Come suggerisce il nome, sono immutabili, quindi il codice seguente causerà un errore in fase di compilazione.
let c = 1 c = 3 // error
Altri tipi possono anche essere dichiarati come costanti. Ad esempio, il codice seguente dichiara un array come una costante e, se tenti di modificare uno qualsiasi degli elementi, il compilatore Swift segnalerà un errore:
var arr2 = [4, 5, 6] arr2[0] = 8 print (arr2) // [8, 5, 6] let arr = [1, 2, 3] a[0] = 5 // error
Optional
Le costanti devono essere inizializzate quando le dichiarano e le variabili devono essere inizializzate prima dell'uso. Allora, dov'è l'equivalente nil
dell'Obiettivo-C? Swift introduce valori opzionali . I valori facoltativi possono avere un valore o essere nil
. Se dai un'occhiata al codice seguente, noterai che a x
è stato assegnato un valore Optional
di 2014
. Ciò significa che il compilatore Swift era consapevole che x
potrebbe anche essere nil
.
var s = "2014" var x = s.toInt() print(x) // Optional(2014)
Se apporti una modifica a questo codice e assegni il valore "abc"
a s
, che non può essere convertito in un intero, noterai che x
ora è nil
.
var s = "abc" var x = s.toInt() print(x) // nil
Il tipo restituito della funzione toInt()
è Int?
, che è un Int . Proviamo a chiamare una funzione standard su x
:
var x = "2014".toInt() print(x.successor()) // error
Il compilatore segnala un errore, poiché x
è un optional e potrebbe potenzialmente essere nil . Dobbiamo prima testare x
e assicurarci che la funzione successor
sia invocata su un numero reale e non su un valore nil
:
var x = "2014".toInt() if x != nil { print(x!.successor()) // 2015 }
Nota che dobbiamo scartare x
aggiungendo un punto esclamativo (!) . Quando siamo sicuri che x
contenga un valore, possiamo accedervi. Altrimenti otterremo un errore di runtime. Possiamo anche fare ciò che Swift chiama optional binding , convertendo l'optional in una variabile non opzionale
let x = "123".toInt() if let y = x { print(y) }
Il codice nell'istruzione if
verrà eseguito solo se x
ha un valore e lo assegnerà a y
. Nota che non è necessario scartare y
, il suo tipo non è facoltativo poiché sappiamo che x
non è nil
.
Controlla il tutorial Swift di Apple per leggere maggiori dettagli sugli optional e su funzioni interessanti come il concatenamento opzionale
Interpolazione di stringhe
In Objective-C la formattazione delle stringhe viene solitamente eseguita con il metodo stringWithFormat:
:
NSString *user = @"Gabriel"; int days = 3; NSString *s = [NSString stringWithFormat:@"posted by %@ (%d days ago)", user, days];
Swift ha una funzione chiamata interpolazione di stringhe per fare lo stesso, ma è più compatto e più facile da leggere:
let user = "Gabriel" let days = 3 let s = "posted by \(user) \(days) ago"
Puoi anche usare le espressioni:
let width = 2 let height = 3 let s = "Area for square with sides \(width) and \(height) is \(width*height)"
Per saperne di più sull'interpolazione delle stringhe di Swift e altre nuove funzionalità, vai qui.
Funzioni
La definizione di funzione in Swift è diversa da C. Di seguito è riportata una definizione di funzione di esempio:
func someFunction(s:String, i: Int) -> Bool { ... // code }
Le funzioni Swift sono tipi di prima classe . Ciò significa che puoi assegnare funzioni alle variabili, passarle come parametri ad altre funzioni o farle restituire tipi:
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
Ancora una volta, Swift deduce i tipi di f1
e f2
( String
-> Int
), anche se avremmo potuto definirli esplicitamente:
let f1:String -> Int = stringLength
Le funzioni possono anche restituire altre funzioni:
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))
Una guida alle funzioni in Swift può essere trovata qui.
Enumerazioni
Le enumerazioni in Swift sono molto più potenti che in Objective-C. Come struttura Swift, possono avere metodi e vengono passati per valore:
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"
A differenza di Objective-C, le enumerazioni Swift possono assegnare stringhe, caratteri o float come valori per ciascun membro, oltre ai numeri interi. Il comodo metodo toRaw()
restituisce il valore assegnato a ciascun membro.
Le enumerazioni possono anche essere parametrizzate:
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)"
Maggiori informazioni sulle enumerazioni sono disponibili qui.

Tuple
Le tuple raggruppano più valori in un unico valore composto. I valori all'interno di una tupla possono essere di qualsiasi tipo e non devono essere dello stesso tipo l'uno dell'altro.
let person = ("Gabriel", "Kirkpatrick") print(person.0) // Gabriel
Puoi anche nominare i singoli elementi della tupla:
let person = (first: "Gabriel", last: "Kirkpatrick") print(person.first)
Le tuple sono estremamente convenienti come tipi restituiti per le funzioni che devono restituire più di un valore:
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
A differenza di Objective-C, Swift supporta la corrispondenza dei modelli in un'istruzione 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") }
Nel secondo caso non ci interessa la parte reale del numero, quindi usiamo un _
per abbinare qualsiasi cosa. Puoi anche verificare la presenza di condizioni aggiuntive in ogni caso. Per questo dobbiamo associare i valori del modello alle costanti:
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)") }
Nota come dobbiamo vincolare solo i valori che useremo nel confronto o nell'istruzione case.
Per saperne di più sulle tuple, vai qui.
Classi e strutture
A differenza di Objective-C, Swift non richiede la creazione di file di interfaccia e di implementazione separati per classi e strutture personalizzate. Man mano che impari Swift, imparerai a definire una classe o una struttura in un singolo file e l'interfaccia esterna a quella classe o struttura viene resa automaticamente disponibile per l'uso di altro codice.
Definire le classi
Le definizioni delle classi sono molto semplici:
class Bottle { var volume: Int = 1000 func description() -> String { return "This bottle has \(volume) ml" } } let b = Bottle() print(b.description())
Come puoi vedere, la dichiarazione e l'implementazione sono nello stesso file . Swift non utilizza più file di intestazione e implementazione. Aggiungiamo un'etichetta al nostro esempio:
class Bottle { var volume: Int = 1000 var label:String func description() -> String { return "This bottle of \(label) has \(volume) ml" } }
Il compilatore si lamenterà perché label è una variabile non opzionale e non conterrà un valore quando viene istanziata una Bottle. Dobbiamo aggiungere un inizializzatore:
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" } }
Oppure, potremmo usare il tipo Optional
per una proprietà, che non deve essere inizializzata. Nell'esempio seguente abbiamo reso il 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)" } } }
Strutture
Anche il linguaggio Swift ha structs
, ma sono molto più flessibili rispetto a Objective-C. L'esercitazione sul codice seguente definisce una 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)" } }
Come le classi in Swift, le strutture possono avere metodi, proprietà, inizializzatori e conformarsi ai protocolli. La principale differenza tra classi e strutture è che le classi vengono passate per riferimento, mentre le strutture vengono passate per valore .
Questo esempio mostra il passaggio di classi per riferimento:
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
Se proviamo un caso simile con struct
, noterai che le variabili vengono passate per valore:
var s1 = Seat(row: 14, letter:"A") var s2 = s1 s1.letter = "B" print(s1.description()) // 14-B print(s2.description()) // 14-A
Quando dovremmo usare struct
e quando dovremmo usare class
? Come in Objective-C e C, usa struct quando devi raggruppare alcuni valori e aspettati che vengano copiati anziché referenziati. Ad esempio, numeri complessi, punti 2D o 3D o colori RGB.
Un'istanza di una classe è tradizionalmente nota come oggetto. Tuttavia, le classi e le strutture Swift sono molto più vicine in termini di funzionalità rispetto ad altri linguaggi e molte funzionalità possono essere applicate a istanze di una classe o di un tipo di struttura. Per questo motivo, il termine più generale utilizzato in Swift reference è instance
, che si applica a ciascuno di questi due.
Impara le basi delle classi e delle strutture Swift qui.
Proprietà
Come abbiamo visto in precedenza, le proprietà in Swift sono dichiarate con la parola chiave var
all'interno di una definizione di classe o struct. Possiamo anche dichiarare costanti con un'istruzione 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
Tieni inoltre presente che le proprietà della classe sono fortemente referenziate, a meno che non le si anteponga la parola chiave weak
. Tuttavia ci sono alcune sottigliezze con deboli proprietà non opzionali, quindi leggi il capitolo sul conteggio automatico dei riferimenti nella guida Swift di Apple.
Proprietà calcolate
Le proprietà calcolate non memorizzano effettivamente un valore. Invece, forniscono un getter e un setter facoltativo per recuperare e impostare indirettamente altre proprietà e valori.
Il codice seguente fornisce un esempio di un sign
di valore calcolato:
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) } } } }
Possiamo anche definire proprietà di sola lettura semplicemente implementando un getter:
struct SomeNumber { var number:Int var isEven:Bool { get { return number % 2 == 0 } } }
In Objective-C, le proprietà sono solitamente supportate da una variabile di istanza, dichiarata in modo esplicito o creata automaticamente dal compilatore. In Swift, invece, una proprietà non ha una variabile di istanza corrispondente . Cioè, non è possibile accedere direttamente al backing store di una proprietà. Supponiamo di avere questo in Objective-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
Poiché, in Swift, le proprietà calcolate non hanno un archivio di supporto, dobbiamo fare qualcosa del genere:
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 } } }
Le proprietà sono spiegate più dettagliatamente qui
Continua
Ci sono molte altre cose importanti da imparare in Swift, come Generics, interazione con le librerie Objective-C, chiusure, concatenamento opzionale e sovraccarico degli operatori. Un singolo tutorial non può descrivere a fondo un nuovo linguaggio, ma non ho dubbi che molto altro verrà scritto sull'apprendimento della programmazione Swift. Tuttavia, credo che questa rapida lettura aiuterà molti sviluppatori di Objective-C, che non sono riusciti a trovare il tempo e ad apprendere i dettagli del linguaggio Swift, a mettersi in carreggiata e lasciare che l'uccello Swift li porti a nuove vette.