Vai al contenuto

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.