Swift optionals

it Il nuovo linguaggio Swift introdotto da Apple alla WWDC 2014 sarà il linguaggio ufficiale con cui sviluppare App per iOS (e per MacOSX).

Già si discute molto se (o quando) l’Objective-C sarà completamente rimpiazzato. Io credo presto, anche se al momento ne abbiamo ancora bisogno per alcune funzionalità non  ancora pronte in Swift (provate a trasformare una stringa in float).

Una delle caratteristiche per me più innovative in Swift sono gli optionals. Per quanto ne so non esiste analogo in altri linguaggi (attendo smentite).

Gli optional sono,  a mio parere, una nuova “attitudine al codice”. Quelli abituati come me fin dai tempi del C a programmare sulla difensiva, a non dare mai per scontato che una variabile fosse “correttamente” inizializzata, anche a noi è capitato comunque di cadere nell’errore: “non doveva mai succedere …”.

Quando inizializziamo una variabile con il risultato di una operazione che “potrebbe non andare a buon fine”, stiamo creando una variabile che potrebbe avere un valore corretto oppure no. In particolare potrebbe avere valore nullo (nil) se l’operazione non va a buon fine (e il codice è scritto bene).

Una seconda tipologia di variabili invece ha la caratteristica di avere sempre un valore diverso da nil.

Un esempio di questa ultima categoria è (in swift):

Possiamo avere la certezza che dopo questa riga a avrà il valore 2 (comunque mai nil).

Ma dopo aver eseguito la seguente riga:

sappiamo che a può contenere un numero, ma anche nil se, per esempio, la stringa myString contiene un testo non trasformabile in intero. E questo può accadere in tanti altri casi: pensate ad una variabile risultato di una apertura di un file, o di una connessione a database etc. (tra l’altro la linea precedente non compila in swift, vediamo in un momento cosa dobbiamo aggiungere).

Fino ad oggi abbiamo sempre avuto cura, in casi come questi, di controllare il valore della variabile subito dopo l’istruzione, per essere sicuri di gestire l’eventuale errore.

Swift addirittura separa concettualmente tutte le variabili/costanti in due gruppi: quelle che possono avere anche il valore nil (optionals), e quelle che non possono avere il valore nil (variabili normali).

Una variabile (o costante) optional ha lo stesso tipo di una variabile “normale” ma con un punto interrogativo aggiuntivo. Scriviamo la linea precedente in modo corretto:

Notate il punto interrogativo dopo Int (ora la linea compila correttamente).

In questo modo Swift ci “costringe” a pensare alla variabile a in un modo diverso: “attenzione dobbiamo controllare se è nil“.

Se per esempio, dopo aver eseguito la riga precedente, scriviamo:

Il compilatore si ferma con l’errore: “Value of optional type ‘Int?’ not unwrapped…“.

Per eseguire il controllo not nil dobbiamo eseguire un unwrap. Cioè prima di usare veramente la variabile la dobbiamo (letteralmente) aprire, “sballare” (appunto unwrap), per vedere cosa c’è veramente dentro.

Notiamo che per Swift nil non è il puntatore ad un oggetto non esistente (come in altri linguaggi), ma è un valore che indica l’assenza di dato, e vale anche per valori che non sono oggetti (es. Int, struct etc…).

Unwrap forzato

Nell’unwrap forzato, controlliamo noi la consistenza della variabile e, con un punto esclamativo (!) dopo il nome della variabile, diciamo al compilatore di trattarla come una variabile normale.

In questo caso stiamo “silenziando” il compilatore e ci assumiamo la responsabilità garantendo per il valore di a. In questo caso abbiamo controllato con un if la validità di a.

Dobbiamo usare l’ unwrap forzato solo quando siamo sicuri di quello che stiamo facendo (come nel codice precedente). Infatti se eseguiamo un unwrap forzato su una variabile che si rivela poi avere il valore nil, avremo certamente un crash della app al runtime: “fatal error: unexpectedly found nil while unwrapping an Optional value“.

Optional binding

L’optional binding è una sintassi con cui eseguiamo l’unwrap e indichiamo:

  • il blocco da eseguire se la variabile non è nil
  • il nome di una nuova variabile, risultato dell’unwrap

Il blocco dentro l’if viene eseguito solo se l’optional a ha un valore diverso da nil, altrimenti il blocco viene ignorato.

La variabile risultato dell’unwrap è: _a ed è quella che usiamo internamente al blocco, la unwrapped di a. Il modo in cui nominiamo questa secondo variabile, il cui scope è il blocco stesso, dipende dalla naming convention del programmatore. In questo caso ho aggiunto un underscore al nome della variabile ma avrei anche potuto chiamarla a_unwrapped, oppure a_opt (l’originale) e a (la unwrapped), o altro ancora. Non ho ancora visto indicazioni in proposito da Apple e, per ora, ci affidiamo alla nostra nomenclatura preferita.

Unwrap implicito

In alcuni casi siamo sicuri che il dato non contenga nil già al momento della dichiarazione, per esempio guardiamo il codice:

In questo caso a non potrà essere nil, ma il metodo toInt() torna per definizione un optional, come ne usciamo?

Inseriamo il punto esclamativo (!) dopo il tipo della variabile e a questo punto possiamo usare a senza dover eseguire un ulteriore unwrap.

Questa operazione viene detta “unwrap implicito” e valgono le stesse considerazioni dell’unwrap forzato riguardo eventuali errori al runtime qualora a si rivelasse nil in qualche caso.

Optional chaining

In presenza di una variabile optional è possibile, senza eseguire l’unwrap, richiamare metodi o proprietà della variabile stessa usando il carattere punto interrogativo (?) dopo il nome della variabile.

Nel seguente codice apriamo un file e analizziamo il suo contenuto.

SI noti che la variabile fileContent è un optional (l’apertura del file potrebbe tornare nil). Nella seconda riga stiamo usando l’optional chaining, cioè stiamo richiamando su questa variabile il metodo componentsSeparatedByString senza fare un unwrap.

Il carattere ? dopo il nome della variabile e prima del metodo, indica di eseguire il metodo solo se la variabile contiene un valore (<> nil).

E’ possibile aggiungere metodi e proprietà dopo il primo (chaining) e l’esecuzione si fermerà al primo optional che si rivela nil. Se questo accade l’intero risultato dell’operazione sarà nil (nel nostro esempio infatti linesArray sarà  a sua volta un optional).

Reference

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  

Valerio Ferrucci

Valerio Ferrucci (valfer) develops software on Apple Macintosh since the 1990s until today for MacOS, OSX and, since some years, iOS. He is also a Web (PHP/MySQL/JS/CSS) and Android Developer.

More Posts - Website

Follow Me:
TwitterFacebookLinkedIn

Leave a Reply

Your email address will not be published. Required fields are marked *