swift

Classi e strutture sono le fondamenta di ogni programma. All'interno delle classi e delle strutture vengono definite le proprietà e i metodi con la stessa sintassi con cui si definiscono le variabili e le funzioni.

A differenza di altri linguaggi, dove per le classi è necessario creare un codice per l'interfaccia e un codice per l'implementazione, in Swift è sufficiente definire il corpo della classe.

La differenza principale tra classe e struttura è che la prima lavora per riferimento, la seconda per valore. Ovvero quando viene creata un'istanza di una classe viene creato un riferimento alla zona di memoria occupata dalla classe, quando viene creata un'istanza di una struttura tutta la struttura viene copiata nella nuova istanza.

Definire una classe o una struttura è sintatticamente uguale. E' necessario prestare attenzione alle convenzioni utilizzate in Swift. Classi e strutture sono a tutti gli effetti dei tipi, quindi per la convenzione del linguaggio Swift,  la nomenclatura utilizza il metodo UpperCamelCase.

struct SugoPomodoro {

    var pomodoro = 0

    var cipolla = 0

    var sale = 0

    var basilico = 0

}

class PastaAlPomodoro {

    var sugo = SugoPomodoro()

    var parmigiano = false

    var pasta = 0

    var tipoPasta: String?

}

 

La struttura sopra esposta definisce quattro stored properties inizializzate a 0. Avendo effettuato l'inizializzazione delle quattro variabili in fase di dichiarazione della struttura non è necessario specificare il tipo in quanto viene dedotto dal compilatore.

La classe PastaAlPomodoro ha quattro stored properties. La prima, il sugo, viene inizializzata con una nuova istanza della struttura SugoPomodoro che rappresenza anche il tipo della variabile sugo. Parmigiano è una variabile booleana di valore false. La quantità di pasta è inizializzata a zero. Il tipoPasta non viene specificato ed è una variabile opzionale (quindi terminata con ?) di tipo string; in fase di inizializzazione il compilatore le assegna il valore nil.

In questo momento abbiamo definito una struttura e una classe ma non è stata ancora effettuata alcuna operazione su di loro. Per poter agire su classi e strutture occorre istanziarle e inizializzarle. L'inizializzazione avviene facendo seguire il nome della classe o struttura dalle parentesi tonde.

var delSugo = SugoPomodoro()

let dellaPasta = PastaAlPomodoro()

 

Alcuni passaggi per accedere alle proprietà:

print(delSugo.basilico) //Stampa 0

print(dellaPasta.parmigiano) //Stampa false

print(dellaPasta.sugo.basilico) //Stampa 0

delSugo.basilico = 4 //Assegna alla proprietà basilico il valore 4

dellaPasta.sugo.basilico = 4 //uguale

 

Il codice sopra esposto può sembrare banale, ma nasconde un'insidia. I primi tre print stampano delle proprietà presenti nelle istanze della struttura delSugo e della classe dellaPasta. Alla quarta riga modifico il valore della proprietà basilico (assegnandogli il valore 4) questo è possibile in quanto delSugo è stato precedentemente definito come variabile; se l'avessi definito tramite la parola chiave let, cioè costante, questo avrebbe dato origine ad un errore. Al contrario la classe dellaPasta pur essendo definita costante accetta il cambiamento del valore della proprietà. Questo è possibile in quanto con l'istanza di una classe faccio riferimento all'indirizzo in memoria della classe, che è stato definito costante, non ai valori in essa contenuti. Tutto questo per mettere ancora in rilievo la differenza che c'è tra classe e struttura.

Due istanze della stessa struttura sono di fatto due strutture interamente copiate nelle variabili definite, le due variabili risultano indipendenti e svincolate.

Due istanze della stessa classe sono due riferimenti che convergono sullo stesso gruppo di dati (o locazione di memoria) di conseguenza le modifiche che effettuo sulle proprietà della prima istanza si vedono sulla seconda. Per verificare se due variabili fanno riferimento alla stessa istanza della classe si usa il simbolo "identico" composto dal carattere '=' ripetuto tre volte (es: var1 === var2).

E' necessario approfondire il tema inizializzazione in quanto sia nella struttura che nella classe ho assegnato valori iniziali di default. Questo metodo è valido ed è anche consigliato per come viene gestito dal compilatore, ma può essere utilizzato solo se si ha la necessità di inizializzare la struttura sempre con gli stessi valori. Nel caso ogni volta che viene creata una classe o struttura devo attribuire alle proprietà valori specifici è opportuno l'utilizzo di un inizializzatore. Si veda l'esempio che segue.

enum Lettori {

    case magnetico

    case rfid

    case combo

}

 

struct Terminale {

    let nome: String

    var tipoLettore: Lettori

    var display: Bool

    var tastiera: Bool

    

    init(nome:String, tipoLettore: Lettori, display: Bool, tastiera: Bool) {

        self.nome = nome

        self.tipoLettore = tipoLettore

        self.display = display

        self.tastiera = tastiera

    }

 

    init(nome:String, display: Bool, tastiera: Bool) {

        self.nome = nome

        self.tipoLettore = Lettori.combo

        self.display = display

        self.tastiera = tastiera

    }

}

 

var myTerm = Terminale(nome: "TR1", tipoLettore: Lettori.combo, display: true, tastiera: true)
var myTerm2 = Terminale(nome: "TR2", display: true, tastiera: true)

 

Nell'esempio sopra esposto c'è un'altro elemento da non sottovalutare: la possibilità di definire più inizializzatori con parametri differenti. In funzione del numero o dell'etichetta dei parametri il compilatore sceglierà l'inizializzatore opportuno.