OPZIONALI¶
Cosa imparerò:
- Perché utilizzare optional
- Forzare un oggetto optional
- if-let e guard-let
Swift ci dà la possibilità di controllare se un dato è presente o meno. Grazie agli opzionali possiamo gestire questi casi, ed evitare di avere comportamenti anomali nelle nostre app.
Un opzionale rappresenta due possibilità, ovvero il valore potrebbe esserci o meno. Possiamo utilizzare il ? quando andiamo a creare una proprietà, per esempio all’interno di una struct:
struct Film {
var nome: String
var dataUscita: String?
}
E quando creiamo un’istanza se il valore non è presente possiamo utilizzare la keyword nil, ovvero il valore non è presente.
var movie = Film(nome: "Titolo", dataUscita: nil)
Nel caso volessimo creare una variabile che sia nil, a cui verrebbe dato il valore in un secondo momento, dovremo specificarne il tipo:
var acceso: Bool? = nil
Per forzare un oggetto opzionale, ovvero nel caso di un oggetto che pensiamo abbia un valore andremo ad utilizzare il !, dobbiamo però stare attenti perché se la variabile viene forzata e non c’è un valore, l’app avrà un arresto anomalo.
print("acceso \(acceso!)")
Output
__lldb_expr_63/MyPlayground.playground:26: Fatal error: Unexpectedly found nil while unwrapping an Optional value
In questi casi si utilizza la sintassi dell’if-let:
if let on = acceso {
print("acceso \(on)")
} else {
print("acceso è nil")
}
Output
acceso è nil
O del guard let:
func isOn() {
guard let on = acceso else {
print("acceso è nil")
return
}
print("acceso \(on)")
}
isOn()
Output
acceso è nil
Nel guard-let, se acceso ha un valore verrà assegnato alla costante temporanea on, e verrà eseguito il codice successivo alle parentesi graffe dell'else, se non è presente un valore il compilatore eseguirà il codice nell'else e con il return il compilatore non eseguirà nessun altro codice che è prensente nella funzione, ed eviteremo problemi nell’app.
Possiamo rendere opzionali anche parametri in ingresso ed in uscita di una funzione:
func saluta(nome: String?) -> String? {
if let name = nome {
return "Ciao \(name)"
} else {
return nil
}
}
print(saluta(nome: "Mary"))
Output
Optional("Ciao Mary")
All’interno delle struct possiamo creare init opzionali, ovvero se non viene riscontrata una condizione all’interno dell’init, ritornerà nil, e l’istanza quindi non avrà valore.
struct Studenti {
var nome: String
var età: Int
init?(nome: String, età: Int) {
if età < 18 {
return nil
} else {
self.nome = nome
self.età = età
}
}
}
var john = Studenti(nome: "John", età: 16)
var dean = Studenti(nome: "Dean", età: 30)
print(john)
print(dean)
Output
nil
Optional(__lldb_expr_83.Studenti(nome: "Dean", età: 30))
Ora, se età è inferiore a 18, l'initializer restituisce nil, altrimenti viene inizializzata un'istanza di Studenti con i valori forniti.