Compatibile con Xcode 8

Type Casting in Swift. Convertire un oggetto da un Tipo all’altro

La programmazione ad oggetti è quella con cui ti ritroverai a lavorare quotidianamente con le tue applicazioni. L’ho già ribadito nel corso delle varie lezioni e mi piace farlo ancora.

I componenti di un’applicazione sono tutte classi che poi vengono istanziate in oggetti. Pensa per esempio ad un bottone. Questo è generalmente composto da una forma, più o meno rettangolare e da un titolo. Ha un colore di sfondo, un font per il testo e altre varie caratteristiche.

Quindi, la programmazione ad oggetti ha riscontri che vanno oltre quello che potresti pensare. Cioè, se stai pensando che tutte queste lezioni sulla OOP siano un modo in più per scrivere codice, beh, ti sbagli. La programmazione ad oggetti, non è un modo è il modo. 

Per questo motivo è necessario approfondire meglio l’argomento dato che questo modulo è quello che realmente ti inizializza allo sviluppo delle app.

Come si apre, ti introduco l’argomento di oggi con una domanda.

La domanda è la seguente: due oggetti, istanza della stessa classe, sono uguali?

Purtroppo non puoi e non troverai mai un sistema che ti dica quando un oggetto A è uguale, o no, ad un oggetto B.

Il motivo se ci pensi è abbastanza semplice, se lo estendi alla concezione generale che ti ho dato, io sono un oggetto e pur essendo simile ad un altro individuo non sarò mai tale e quale a lui. La stessa logica è stata ripresa e si ripercuote sugli oggetti di un linguaggio di programmazione come Swift.

Però, e come sempre ce n’è uno, un oggetto far parte di una famiglia, che hai chiamato classe, che ne descrive le caratteristiche generali.

Questo vuol dire che, pur non potendo confrontare due oggetti tra loro, è possibile verificare se quell’oggetto è istanza di una classe oppure no.

L’argomento che tratterò in questa lezione si chiama Type Casting in Swift e ti permetterà di analizzare il tipo di una classe, is a type of, oppure di trasformare un oggetto, istanza di una classe della sua gerarchia, in un altro della gerarchia delle classi a cui appartiene.

Type Casting in Swift

Cos’è il Type Casting

Al solito, ragioniamo con un esempio reale.

Realizziamo insieme la struttura delle classi di un progetto, che riguarda la realizzazione di un’applicazione di gestione appunti, cui è possibile inserire all’interno oggetti di tipo: Audio e Testuali (Più o meno come l’esercizio assegnato alla fine della lezione sull’ereditarietà della classi).

La struttura che ho in mente, per poter realizzare quest’app, è qualcosa che fa capo alla superclasse Nota che si può ramificare in 3 sottoclassi: Audio, Video e Testo.

Ricordati sempre che un’ottima struttura delle classi, anche se funzionale al tipo di progetto che stai realizzando, dipende da un buono studio delle soluzioni applicabili. Mi spiego meglio!

Lo stesso esercizio poteva essere risolto creando 3 classi non ereditate. Però, avere 3 classi differenti significherebbe avere tre tipi di oggetti completamente diversi tra loro che non si assomiglierebbero neanche per il tipo di classe che gli fa da genitore.

Invece, nella struttura che sto utilizzando io, ad esempio, un oggetto Audio, figlio della classe Nota, avrà comunque una interrelazione con gli altri perché figli dello stesso padre.

Un po’ come dire: io e mio fratello, pur essendo diversi, siamo simili perché abbiamo lo stesso patrimonio genetico ereditato dai nostri genitori.

Quindi la struttura delle classi che devi riportare nel tuo playground è la seguente:

La struttura è fatta!

Relazione dei Tipi tra Padre e Figli

Adesso serve qualcosa che ti permette di gestire tutti questi oggetti in maniera efficiente.

Per questo la scelta più saggia sarebbe quella di creare un array che abbia al suo interno sia oggetti di tipo Audio che di tipo Testo:

Qual’è il tipo di dato di quest’array?

Dato che gli oggetti contenuti sono di tipo Testo o Audio e dato che un array, come qualsiasi variabile, può essere descritta solo da un tipo di dato, quello che li rappresenta entrambi è il tipo Nota.

Questo è possibile grazie alla ereditarietà inversa di un oggetto.

Se sul playground inizi a scrivere la parola “appunti” vedrai comparire il suggerimento automatico che affianca al nome della variabile il tipo contenuto in quella variabile, che di fatto è Nota:

type casting in swift

Peppe, questo vuol dire che gli elementi vengono convertiti in oggetti Nota?

Non proprio!

Le classi che ereditano da una classe super, per le regole enunciate nella lezione dell’inheritance di una classe, specializzano il comportamento della classe genitore e, di conseguenza, con la classe super è sempre possibile descrivere le classi figlie.

Con un oggetto di tipo superclasse è sempre possibile immagazzinare un oggetto di tipo subclass:

Come nell’esempio, con un oggetto di tipo Nota sei riuscito a salvare un oggetto di tipo Testo.

Il contrario non può valere in nessuna circostanza! Se lo facesse violerebbe uno dei principi della programmazione ad oggetti cioè quello della specializzazione dei figli (un figlio non può descrivere un padre, il viceversa si). In sostanza è impossibile fare:

Se la variabile notaGenerica è stata inizializzata a Nota, ma viene considerata come un Testo, dove finiscono i suoi attributi?

Type Casting linguaggio swift, classi padre e relazione con figli

Definizione

In realtà le informazioni non vengono perse perché non è avvenuta nessun tipo di conversione (a discapito di quello che si può pensare). Quello che è avvenuto è stato solo un cambio del tipo di riferimento con cui viene considerato quell’oggetto.

Cambiare il riferimento del tipo di dato con cui trattare un oggetto, prende il nome di Type Casting.

Casting: cambiamento e Type: tipo. Quindi dire che un oggetto B ha subito un type casting equivale a dire che è stato cambiato il tipo dell’oggetto B in un tipo della sua gerarchia.

Adesso puoi affermare che, nel caso dell’array appunti, è stato effettuato un type casting!

Down casting

Per poter riconsiderare, più che convertire, un oggetto nel suo rispetto tipo di dato si utilizza la parola chiave as! che esegue il casting e ti da un feedback sul risultato della conversione.

Si parla di Down Casting perché la conversione può avvenire solamente da un tipo più in alto nella gerarchia delle classi ad un tipo più basso. 

Per esempio, un oggetto di tipo Nota potrebbe contenere un oggetto Testo perché è una sua subclass. Mentre un oggetto Testo non potrebbe mai descrivere un oggetto superiore perché, per definizione, una subclass aggiunge qualcosa in più che un super non ha.

Quindi scrivere nomeOggeto as nomeClasse ti permette di riconsiderare un oggetto di un tipo A come un oggetto di un tipo B:

Fa in modo che l’oggetto venga convertito in uno dei type permessi dalla struttura delle classi di cui fa parte il tipo di dato dell’oggetto in questione.

Nell’esempio:

  1. Alla prima riga viene eseguito un type casting di tipo implicito ovvero: dato che la variabile a sinistra, quella a cui verrà assegnato l’oggetto notaGenerica, presenta un tipo di dato esplicito :Nota, la variabile a destra viene automaticamente convertita nel nuovo tipo di dato perché Testo fa parte della gerarchia in cui è presente anche la classe Nota.
  2. Alla seconda riga di codice, la var testo non presenta un tipo esplicito quindi se notaGenerica non venisse convertita nel tipo Testo, con l’operatore as, sarebbe considerata come Nota.

Down Casting esplicito linguaggio swift

Down casting opzionale

Nel precedente esempio è andato tutto bene perché noi conoscevamo a priori la struttura delle classi. E se questa non fosse nota? L’operatore di down casting funzionerebbe comunque?

Guarda questo esempio:

Esce fuori un errore enorme quanto una casa.

L’Up Casting è impossibile. Cioè non puoi specializzare un oggetto generale, come uno della classe Nota, in uno delle sue sottoclassi.

Se non conosci la struttura delle classi, come in molti casi in cui svilupperai applicazioni, è necessario avere uno strumento che permetta di evitare la generazione d’errore in un’operazione di casting.

L’operatore as si presenta anche nella forma opzionale, quindi come as? e funziona così:

  1. Restituisce nil se l’operazione di casting non può essere effettuata o perché l’oggetto in questione non fa parte della gerarchia oppure perché si sta tentando un Up Casting.
  2. Converte il tipo di dato se il casting è permesso.

L’esempio sopra può essere risolto così:

Se fai un print della variabile testoGenerico ti accorgerai che stamperà nil perché l’operazione di casting non è stata possibile.

Applicando queste ultime nozioni apprese, puoi finalmente eseguire un down casting sugli elementi contenuti all’interno dell’array appunti per poter stampare le informazioni relative ai reali valori contenuti dagli elementi:

Nota come, con l’operatore as opzionale, sei riuscito ad iterare tutti gli elementi dell’array.

Down casting opzionale linguaggio swift

Checking Type

L’operatore is effettua un controllo, restituendo true o false, se l’oggetto in esame è un’istanza di una determinata subclass o classe.

Sempre considerando l’esempio dell’applicazione, immagina di voler contare gli oggetti Testo e Audio presenti all’interno dell’array. Con l’operatore is, l’esercizio si risolve nella seguente maniera:

Dato che gli elementi contenuti nell’array appunti hanno subito un down casting implicito, quindi sono stati convertiti in oggetti Nota, con l’operatore is sei in grado di verificare se l’oggetto, passato in rassegna dal ciclo, è un’istanza di una sottoclasse ben specifica (o Testo o Audio).

Fai attenzione perché la differenza tra as e is è sostanziale:

  • as: converte il tipo di dato dell’oggetto in questione in un nuovo tipo.
  • is: verifica se un oggetto appartiene o no ad una istanza di una classe.

La conversione implica un dispendio di energie, mentre un confronto (lo puoi paragonare ad un if) non costa praticamente nulla.

Type Checking linguaggio swift

Considerazioni

Il Type Casting con il linguaggio Swift, come in qualsiasi altro linguaggio di programmazione, è uno dei principali problemi d’errore di un’applicazione. Quindi ti invito a prestare attenzione ai tipi di dato con cui andrai a lavorare.

In generale, se non sei sicuro che un down casting avrà successo, utilizza sempre l’operatore as opzionale as? e solo quando sei sicurissimo del risultato as! non opzionale.

Ricordati che un casting impossibile da eseguire genererà sempre un errore. Quindi presta attenzione ai tipi.

Nella prossima lezione, l’ultima che ti da un quadro completo delle feature del linguaggio Swift, vedrai come gestire i vari errori con il comando più famoso al mondo: do-try-catch.

Buona Programmazione!

Changelog

  • 9/11/2016 – Aggiunto il changelog. Eliminate alcune parti superflue e verificata la compatibilità con Swift 3.0 ed Xcode 8.

Torna a: Corso gratuito linguaggio di programmazione Swift > Programmazione ad oggetti in Swift

Start typing and press Enter to search

Extension e Protocol in SwiftCome creare una applicazione di Foto Editing per iOS con Swift.