> For the complete documentation index, see [llms.txt](https://swift.unicorndonkeys.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://swift.unicorndonkeys.com/guida-al-linguaggio/inizializzazione.md).

# Inizializzazione (Initialization)

Imposta i valori iniziali delle proprietà memorizzate di un tipo ed esegui una configurazione una tantum.

L'*inizializzazione* è il processo di preparazione all'uso di un'istanza di una classe, una struttura o un'enumerazione. Questo processo comporta l'impostazione di un valore iniziale per ciascuna proprietà memorizzata di quell'istanza e l'esecuzione di qualsiasi altra configurazione o inizializzazione necessaria prima che la nuova istanza sia pronta all'uso.

Implementi questo processo di inizializzazione definendo degli *inizializzatori*, che sono come metodi speciali che possono essere chiamati per creare una nuova istanza di un tipo particolare. A differenza degli inizializzatori di Objective-C, gli inizializzatori di Swift non restituiscono un valore. Il loro ruolo principale è garantire che le nuove istanze di un tipo siano inizializzate correttamente prima di essere usate per la prima volta.

Le istanze dei tipi classe possono anche implementare un *deinizializzatore*, che esegue qualsiasi pulizia personalizzata subito prima che un'istanza di quella classe venga deallocata. Per maggiori informazioni sui deinizializzatori, vedi [Deinizializzazione](/guida-al-linguaggio/deinizializzazione.md).

## Impostare i valori iniziali delle proprietà memorizzate <a href="#impostare-i-valori-iniziali-delle-proprieta-memorizzate" id="impostare-i-valori-iniziali-delle-proprieta-memorizzate"></a>

Classi e strutture *devono* impostare tutte le loro proprietà memorizzate a un valore iniziale appropriato entro il momento in cui viene creata un'istanza di quella classe o struttura. Le proprietà memorizzate non possono essere lasciate in uno stato indeterminato.

Puoi impostare un valore iniziale per una proprietà memorizzata all'interno di un inizializzatore, oppure assegnando un valore predefinito alla proprietà come parte della sua definizione. Queste azioni sono descritte nelle sezioni seguenti.

{% hint style="info" %}
**Nota:** Quando assegni un valore predefinito a una proprietà memorizzata, o ne imposti il valore all'interno di un inizializzatore, il valore di quella proprietà viene impostato direttamente, senza chiamare alcun osservatore di proprietà.
{% endhint %}

### Inizializzatori <a href="#inizializzatori" id="inizializzatori"></a>

Gli *inizializzatori* vengono chiamati per creare una nuova istanza di un tipo particolare. Nella sua forma più semplice, un inizializzatore è come un metodo di istanza senza parametri, scritto usando la parola chiave `init`:

```swift
init() {
    // esegui qui qualche inizializzazione
}
```

L'esempio seguente definisce una nuova struttura chiamata `Fahrenheit` per memorizzare temperature espresse nella scala Fahrenheit. La struttura `Fahrenheit` ha una proprietà memorizzata, `temperature`, di tipo `Double`:

```swift
struct Fahrenheit {
    var temperature: Double
    init() {
        temperature = 32.0
    }
}
var f = Fahrenheit()
print("The default temperature is \(f.temperature)° Fahrenheit")
// Stampa "The default temperature is 32.0° Fahrenheit".
```

La struttura definisce un unico inizializzatore, `init`, senza parametri, che inizializza la temperatura memorizzata con un valore di `32.0` (il punto di congelamento dell'acqua in gradi Fahrenheit).

### Valori predefiniti delle proprietà <a href="#valori-predefiniti-delle-proprieta" id="valori-predefiniti-delle-proprieta"></a>

Puoi impostare il valore iniziale di una proprietà memorizzata dall'interno di un inizializzatore, come mostrato sopra. In alternativa, specifica un *valore predefinito della proprietà* come parte della dichiarazione della proprietà. Specifichi un valore predefinito della proprietà assegnandole un valore iniziale quando viene definita.

{% hint style="info" %}
**Nota:** Se una proprietà assume sempre lo stesso valore iniziale, fornisci un valore predefinito anziché impostare un valore all'interno di un inizializzatore. Il risultato finale è lo stesso, ma il valore predefinito lega l'inizializzazione della proprietà più strettamente alla sua dichiarazione. Rende gli inizializzatori più brevi e più chiari e ti permette di inferire il tipo della proprietà dal suo valore predefinito. Il valore predefinito ti rende anche più facile avvalerti degli inizializzatori predefiniti e dell'ereditarietà degli inizializzatori, come descritto più avanti in questo capitolo.
{% endhint %}

Puoi scrivere la struttura `Fahrenheit` vista sopra in una forma più semplice fornendo un valore predefinito per la sua proprietà `temperature` nel punto in cui la proprietà viene dichiarata:

```swift
struct Fahrenheit {
    var temperature = 32.0
}
```

## Personalizzare l'inizializzazione <a href="#personalizzare-linizializzazione" id="personalizzare-linizializzazione"></a>

Puoi personalizzare il processo di inizializzazione con parametri di input e tipi di proprietà opzionali, oppure assegnando proprietà costanti durante l'inizializzazione, come descritto nelle sezioni seguenti.

### Parametri di inizializzazione <a href="#parametri-di-inizializzazione" id="parametri-di-inizializzazione"></a>

Puoi fornire dei *parametri di inizializzazione* come parte della definizione di un inizializzatore, per definire i tipi e i nomi dei valori che personalizzano il processo di inizializzazione. I parametri di inizializzazione hanno le stesse capacità e la stessa sintassi dei parametri di funzioni e metodi.

L'esempio seguente definisce una struttura chiamata `Celsius`, che memorizza temperature espresse in gradi Celsius. La struttura `Celsius` implementa due inizializzatori personalizzati chiamati `init(fromFahrenheit:)` e `init(fromKelvin:)`, che inizializzano una nuova istanza della struttura con un valore proveniente da una scala di temperatura diversa:

```swift
struct Celsius {
    var temperatureInCelsius: Double
    init(fromFahrenheit fahrenheit: Double) {
        temperatureInCelsius = (fahrenheit - 32.0) / 1.8
    }
    init(fromKelvin kelvin: Double) {
        temperatureInCelsius = kelvin - 273.15
    }
}
let boilingPointOfWater = Celsius(fromFahrenheit: 212.0)
// boilingPointOfWater.temperatureInCelsius è 100.0
let freezingPointOfWater = Celsius(fromKelvin: 273.15)
// freezingPointOfWater.temperatureInCelsius è 0.0
```

Il primo inizializzatore ha un unico parametro di inizializzazione con etichetta dell'argomento `fromFahrenheit` e nome del parametro `fahrenheit`. Il secondo inizializzatore ha un unico parametro di inizializzazione con etichetta dell'argomento `fromKelvin` e nome del parametro `kelvin`. Entrambi gli inizializzatori convertono il loro unico argomento nel valore Celsius corrispondente e memorizzano questo valore in una proprietà chiamata `temperatureInCelsius`.

### Nomi dei parametri ed etichette degli argomenti <a href="#nomi-dei-parametri-ed-etichette-degli-argomenti" id="nomi-dei-parametri-ed-etichette-degli-argomenti"></a>

Come per i parametri di funzioni e metodi, i parametri di inizializzazione possono avere sia un nome del parametro da usare all'interno del corpo dell'inizializzatore sia un'etichetta dell'argomento da usare quando si chiama l'inizializzatore.

Tuttavia, gli inizializzatori non hanno un nome di funzione identificativo prima delle parentesi come invece hanno funzioni e metodi. Pertanto, i nomi e i tipi dei parametri di un inizializzatore svolgono un ruolo particolarmente importante nell'identificare quale inizializzatore debba essere chiamato. Per questo motivo, Swift fornisce un'etichetta dell'argomento automatica per *ogni* parametro di un inizializzatore se non ne fornisci una.

L'esempio seguente definisce una struttura chiamata `Color`, con tre proprietà costanti chiamate `red`, `green` e `blue`. Queste proprietà memorizzano un valore compreso tra `0.0` e `1.0` per indicare la quantità di rosso, verde e blu nel colore.

`Color` fornisce un inizializzatore con tre parametri di tipo `Double` con nomi appropriati per le sue componenti rossa, verde e blu. `Color` fornisce anche un secondo inizializzatore con un unico parametro `white`, che viene usato per fornire lo stesso valore a tutte e tre le componenti del colore.

```swift
struct Color {
    let red, green, blue: Double
    init(red: Double, green: Double, blue: Double) {
        self.red   = red
        self.green = green
        self.blue  = blue
    }
    init(white: Double) {
        red   = white
        green = white
        blue  = white
    }
}
```

Entrambi gli inizializzatori possono essere usati per creare una nuova istanza di `Color`, fornendo valori con nome per ciascun parametro dell'inizializzatore:

```swift
let magenta = Color(red: 1.0, green: 0.0, blue: 1.0)
let halfGray = Color(white: 0.5)
```

Nota che non è possibile chiamare questi inizializzatori senza usare le etichette degli argomenti. Le etichette degli argomenti devono sempre essere usate in un inizializzatore se sono definite, e ometterle è un errore in fase di compilazione:

```swift
let veryGreen = Color(0.0, 1.0, 0.0)
// questo segnala un errore in fase di compilazione - le etichette degli argomenti sono obbligatorie
```

### Parametri dell'inizializzatore senza etichette degli argomenti <a href="#parametri-dellinizializzatore-senza-etichette-degli-argomenti" id="parametri-dellinizializzatore-senza-etichette-degli-argomenti"></a>

Se non vuoi usare un'etichetta dell'argomento per un parametro dell'inizializzatore, scrivi un trattino basso (`_`) invece di un'etichetta esplicita per quel parametro per sovrascrivere il comportamento predefinito.

Ecco una versione ampliata dell'esempio `Celsius` di [Parametri di inizializzazione](/guida-al-linguaggio/inizializzazione.md#parametri-di-inizializzazione) visto sopra, con un inizializzatore aggiuntivo per creare una nuova istanza di `Celsius` a partire da un valore `Double` già espresso nella scala Celsius:

```swift
struct Celsius {
    var temperatureInCelsius: Double
    init(fromFahrenheit fahrenheit: Double) {
        temperatureInCelsius = (fahrenheit - 32.0) / 1.8
    }
    init(fromKelvin kelvin: Double) {
        temperatureInCelsius = kelvin - 273.15
    }
    init(_ celsius: Double) {
        temperatureInCelsius = celsius
    }
}
let bodyTemperature = Celsius(37.0)
// bodyTemperature.temperatureInCelsius è 37.0
```

La chiamata all'inizializzatore `Celsius(37.0)` è chiara nelle sue intenzioni senza bisogno di un'etichetta dell'argomento. È quindi appropriato scrivere questo inizializzatore come `init(_ celsius: Double)` in modo che possa essere chiamato fornendo un valore `Double` senza nome.

### Tipi di proprietà opzionali <a href="#tipi-di-proprieta-opzionali" id="tipi-di-proprieta-opzionali"></a>

Se il tuo tipo personalizzato ha una proprietà memorizzata a cui è logicamente consentito avere “nessun valore” — magari perché il suo valore non può essere impostato durante l'inizializzazione, o perché le è consentito avere “nessun valore” in un momento successivo — dichiara la proprietà con un tipo *opzionale*. Le proprietà di tipo opzionale vengono inizializzate automaticamente con un valore `nil`, per indicare che la proprietà è deliberatamente destinata ad avere “nessun valore per ora” durante l'inizializzazione.

L'esempio seguente definisce una classe chiamata `SurveyQuestion`, con una proprietà `String` opzionale chiamata `response`:

```swift
class SurveyQuestion {
    var text: String
    var response: String?
    init(text: String) {
        self.text = text
    }
    func ask() {
        print(text)
    }
}
let cheeseQuestion = SurveyQuestion(text: "Do you like cheese?")
cheeseQuestion.ask()
// Stampa "Do you like cheese?"
cheeseQuestion.response = "Yes, I do like cheese."
```

La risposta a una domanda di un sondaggio non può essere nota finché la domanda non viene posta, e quindi la proprietà `response` è dichiarata con un tipo `String?`, ovvero “`String` opzionale”. Le viene assegnato automaticamente un valore predefinito `nil`, che significa “nessuna stringa per ora”, quando viene inizializzata una nuova istanza di `SurveyQuestion`.

### Assegnare proprietà costanti durante l'inizializzazione <a href="#assegnare-proprieta-costanti-durante-linizializzazione" id="assegnare-proprieta-costanti-durante-linizializzazione"></a>

Puoi assegnare un valore a una proprietà costante in qualsiasi momento durante l'inizializzazione, purché venga impostata a un valore definito entro la fine dell'inizializzazione. Una volta che a una proprietà costante è stato assegnato un valore, non può essere ulteriormente modificata.

{% hint style="info" %}
**Nota:** Per le istanze di classe, una proprietà costante può essere modificata durante l'inizializzazione solo dalla classe che la introduce. Non può essere modificata da una sottoclasse.
{% endhint %}

Puoi rivedere l'esempio `SurveyQuestion` visto sopra per usare una proprietà costante anziché una proprietà variabile per la proprietà `text` della domanda, per indicare che la domanda non cambia una volta creata un'istanza di `SurveyQuestion`. Anche se la proprietà `text` ora è una costante, può comunque essere impostata all'interno dell'inizializzatore della classe:

```swift
class SurveyQuestion {
    let text: String
    var response: String?
    init(text: String) {
        self.text = text
    }
    func ask() {
        print(text)
    }
}
let beetsQuestion = SurveyQuestion(text: "How about beets?")
beetsQuestion.ask()
// Stampa "How about beets?"
beetsQuestion.response = "I also like beets. (But not with cheese.)"
```

## Inizializzatori predefiniti <a href="#inizializzatori-predefiniti" id="inizializzatori-predefiniti"></a>

Swift fornisce un *inizializzatore predefinito* per qualsiasi struttura o classe che fornisca valori predefiniti per tutte le sue proprietà e non fornisca essa stessa almeno un inizializzatore. L'inizializzatore predefinito crea semplicemente una nuova istanza con tutte le sue proprietà impostate ai loro valori predefiniti.

Questo esempio definisce una classe chiamata `ShoppingListItem`, che incapsula il nome, la quantità e lo stato di acquisto di un articolo di una lista della spesa:

```swift
class ShoppingListItem {
    var name: String?
    var quantity = 1
    var purchased = false
}
var item = ShoppingListItem()
```

Poiché tutte le proprietà della classe `ShoppingListItem` hanno valori predefiniti, e poiché è una classe base senza superclasse, `ShoppingListItem` ottiene automaticamente un'implementazione dell'inizializzatore predefinito che crea una nuova istanza con tutte le sue proprietà impostate ai loro valori predefiniti. (La proprietà `name` è una proprietà `String` opzionale, e quindi riceve automaticamente un valore predefinito `nil`, anche se questo valore non è scritto nel codice.) L'esempio qui sopra usa l'inizializzatore predefinito della classe `ShoppingListItem` per creare una nuova istanza della classe con la sintassi di inizializzazione, scritta `ShoppingListItem()`, e assegna questa nuova istanza a una variabile chiamata `item`.

### Inizializzatori memberwise per i tipi struttura <a href="#inizializzatori-memberwise-per-i-tipi-struttura" id="inizializzatori-memberwise-per-i-tipi-struttura"></a>

I tipi struttura ricevono automaticamente un *inizializzatore memberwise* se non definiscono alcun inizializzatore personalizzato. A differenza di un inizializzatore predefinito, la struttura riceve un inizializzatore memberwise anche se ha proprietà memorizzate prive di valori predefiniti.

L'inizializzatore memberwise è un modo abbreviato per inizializzare le proprietà membro delle nuove istanze di una struttura. I valori iniziali per le proprietà della nuova istanza possono essere passati per nome all'inizializzatore memberwise.

L'esempio seguente definisce una struttura chiamata `Size` con due proprietà chiamate `width` e `height`. Il tipo di entrambe le proprietà viene inferito come `Double` assegnando un valore predefinito di `0.0`.

La struttura `Size` riceve automaticamente un inizializzatore memberwise `init(width:height:)`, che puoi usare per inizializzare una nuova istanza di `Size`:

```swift
struct Size {
    var width = 0.0, height = 0.0
}
let twoByTwo = Size(width: 2.0, height: 2.0)
```

Quando chiami un inizializzatore memberwise, puoi omettere i valori per tutte le proprietà che hanno valori predefiniti. Nell'esempio qui sopra, la struttura `Size` ha un valore predefinito per entrambe le sue proprietà `height` e `width`. Puoi omettere una delle due proprietà o entrambe, e l'inizializzatore usa il valore predefinito per tutto ciò che ometti. Per esempio:

```swift
let zeroByTwo = Size(height: 2.0)
print(zeroByTwo.width, zeroByTwo.height)
// Stampa "0.0 2.0".

let zeroByZero = Size()
print(zeroByZero.width, zeroByZero.height)
// Stampa "0.0 0.0".
```

## Delega degli inizializzatori per i tipi valore <a href="#delega-degli-inizializzatori-per-i-tipi-valore" id="delega-degli-inizializzatori-per-i-tipi-valore"></a>

Gli inizializzatori possono chiamare altri inizializzatori per eseguire parte dell'inizializzazione di un'istanza. Questo processo, noto come *delega degli inizializzatori*, evita di duplicare codice tra più inizializzatori.

Le regole su come funziona la delega degli inizializzatori, e su quali forme di delega sono consentite, sono diverse per i tipi valore e per i tipi classe. I tipi valore (strutture ed enumerazioni) non supportano l'ereditarietà, e quindi il loro processo di delega degli inizializzatori è relativamente semplice, perché possono delegare solo a un altro inizializzatore che forniscono essi stessi. Le classi, invece, possono ereditare da altre classi, come descritto in [Ereditarietà](/guida-al-linguaggio/ereditarieta.md). Ciò significa che le classi hanno responsabilità aggiuntive per garantire che a tutte le proprietà memorizzate che ereditano venga assegnato un valore adeguato durante l'inizializzazione. Queste responsabilità sono descritte più avanti in [Ereditarietà delle classi e inizializzazione](/guida-al-linguaggio/inizializzazione.md#ereditarieta-delle-classi-e-inizializzazione).

Per i tipi valore, usi `self.init` per riferirti ad altri inizializzatori dello stesso tipo valore quando scrivi i tuoi inizializzatori personalizzati. Puoi chiamare `self.init` solo dall'interno di un inizializzatore.

Nota che se definisci un inizializzatore personalizzato per un tipo valore, non avrai più accesso all'inizializzatore predefinito (o all'inizializzatore memberwise, se si tratta di una struttura) per quel tipo. Questo vincolo previene una situazione in cui una configurazione essenziale aggiuntiva fornita in un inizializzatore più complesso venga accidentalmente aggirata da qualcuno che usa uno degli inizializzatori automatici.

{% hint style="info" %}
**Nota:** Se vuoi che il tuo tipo valore personalizzato sia inizializzabile con l'inizializzatore predefinito e con l'inizializzatore memberwise, e anche con i tuoi inizializzatori personalizzati, scrivi i tuoi inizializzatori personalizzati in un'estensione anziché come parte dell'implementazione originale del tipo valore. Per maggiori informazioni, vedi [Estensioni](/guida-al-linguaggio/estensioni.md).
{% endhint %}

L'esempio seguente definisce una struttura personalizzata `Rect` per rappresentare un rettangolo geometrico. L'esempio richiede due strutture di supporto chiamate `Size` e `Point`, che forniscono entrambe valori predefiniti di `0.0` per tutte le loro proprietà:

```swift
struct Size {
    var width = 0.0, height = 0.0
}
struct Point {
    var x = 0.0, y = 0.0
}
```

Puoi inizializzare la struttura `Rect` seguente in uno di tre modi — usando i valori predefiniti azzerati delle sue proprietà `origin` e `size`, fornendo un punto di origine e una dimensione specifici, oppure fornendo un punto centrale e una dimensione specifici. Queste opzioni di inizializzazione sono rappresentate da tre inizializzatori personalizzati che fanno parte della definizione della struttura `Rect`:

```swift
struct Rect {
    var origin = Point()
    var size = Size()
    init() {}
    init(origin: Point, size: Size) {
        self.origin = origin
        self.size = size
    }
    init(center: Point, size: Size) {
        let originX = center.x - (size.width / 2)
        let originY = center.y - (size.height / 2)
        self.init(origin: Point(x: originX, y: originY), size: size)
    }
}
```

Il primo inizializzatore di `Rect`, `init()`, è funzionalmente uguale all'inizializzatore predefinito che la struttura avrebbe ricevuto se non avesse avuto propri inizializzatori personalizzati. Questo inizializzatore ha un corpo vuoto, rappresentato da una coppia vuota di parentesi graffe `{}`. Chiamare questo inizializzatore restituisce un'istanza di `Rect` le cui proprietà `origin` e `size` sono entrambe inizializzate con i valori predefiniti `Point(x: 0.0, y: 0.0)` e `Size(width: 0.0, height: 0.0)` delle loro definizioni di proprietà:

```swift
let basicRect = Rect()
// l'origine di basicRect è (0.0, 0.0) e la sua dimensione è (0.0, 0.0)
```

Il secondo inizializzatore di `Rect`, `init(origin:size:)`, è funzionalmente uguale all'inizializzatore memberwise che la struttura avrebbe ricevuto se non avesse avuto propri inizializzatori personalizzati. Questo inizializzatore si limita ad assegnare i valori degli argomenti `origin` e `size` alle proprietà memorizzate appropriate:

```swift
let originRect = Rect(origin: Point(x: 2.0, y: 2.0),
    size: Size(width: 5.0, height: 5.0))
// l'origine di originRect è (2.0, 2.0) e la sua dimensione è (5.0, 5.0)
```

Il terzo inizializzatore di `Rect`, `init(center:size:)`, è leggermente più complesso. Inizia calcolando un punto di origine appropriato in base a un punto `center` e a un valore `size`. Poi chiama (o *delega a*) l'inizializzatore `init(origin:size:)`, che memorizza i nuovi valori di origine e di dimensione nelle proprietà appropriate:

```swift
let centerRect = Rect(center: Point(x: 4.0, y: 4.0),
    size: Size(width: 3.0, height: 3.0))
// l'origine di centerRect è (2.5, 2.5) e la sua dimensione è (3.0, 3.0)
```

L'inizializzatore `init(center:size:)` avrebbe potuto assegnare da sé i nuovi valori di `origin` e `size` alle proprietà appropriate. Tuttavia, è più comodo (e più chiaro nelle intenzioni) che l'inizializzatore `init(center:size:)` si avvalga di un inizializzatore esistente che fornisce già esattamente quella funzionalità.

{% hint style="info" %}
**Nota:** Per un modo alternativo di scrivere questo esempio senza definire tu stesso gli inizializzatori `init()` e `init(origin:size:)`, vedi [Estensioni](/guida-al-linguaggio/estensioni.md).
{% endhint %}

## Ereditarietà delle classi e inizializzazione <a href="#ereditarieta-delle-classi-e-inizializzazione" id="ereditarieta-delle-classi-e-inizializzazione"></a>

A tutte le proprietà memorizzate di una classe — comprese le proprietà che la classe eredita dalla sua superclasse — *deve* essere assegnato un valore iniziale durante l'inizializzazione.

Swift definisce due tipi di inizializzatori per i tipi classe per aiutare a garantire che tutte le proprietà memorizzate ricevano un valore iniziale. Sono noti come inizializzatori designati e inizializzatori di convenienza.

### Inizializzatori designati e inizializzatori di convenienza <a href="#inizializzatori-designati-e-inizializzatori-di-convenienza" id="inizializzatori-designati-e-inizializzatori-di-convenienza"></a>

Gli *inizializzatori designati* sono gli inizializzatori principali di una classe. Un inizializzatore designato inizializza completamente tutte le proprietà introdotte da quella classe e chiama un inizializzatore appropriato della superclasse per continuare il processo di inizializzazione risalendo la catena delle superclassi.

Le classi tendono ad avere pochissimi inizializzatori designati, ed è piuttosto comune che una classe ne abbia uno solo. Gli inizializzatori designati sono punti di “imbuto” attraverso cui avviene l'inizializzazione, e attraverso cui il processo di inizializzazione prosegue risalendo la catena delle superclassi.

Ogni classe deve avere almeno un inizializzatore designato. In alcuni casi, questo requisito è soddisfatto ereditando uno o più inizializzatori designati da una superclasse, come descritto più avanti in [Ereditarietà automatica degli inizializzatori](/guida-al-linguaggio/inizializzazione.md#ereditarieta-automatica-degli-inizializzatori).

Gli *inizializzatori di convenienza* sono inizializzatori secondari, di supporto, di una classe. Puoi definire un inizializzatore di convenienza che chiami un inizializzatore designato della stessa classe dell'inizializzatore di convenienza con alcuni dei parametri dell'inizializzatore designato impostati a valori predefiniti. Puoi anche definire un inizializzatore di convenienza per creare un'istanza di quella classe per uno specifico caso d'uso o tipo di valore di input.

Non devi fornire inizializzatori di convenienza se la tua classe non ne ha bisogno. Crea inizializzatori di convenienza ogni volta che una scorciatoia per uno schema di inizializzazione comune farà risparmiare tempo o renderà l'inizializzazione della classe più chiara nelle intenzioni.

### Sintassi degli inizializzatori designati e di convenienza <a href="#sintassi-degli-inizializzatori-designati-e-di-convenienza" id="sintassi-degli-inizializzatori-designati-e-di-convenienza"></a>

Gli inizializzatori designati delle classi si scrivono nello stesso modo dei semplici inizializzatori dei tipi valore:

```swift
init(<#parameters#>) {
   <#statements#>
}
```

Gli inizializzatori di convenienza si scrivono nello stesso stile, ma con il modificatore `convenience` collocato prima della parola chiave `init`, separato da uno spazio:

```swift
convenience init(<#parameters#>) {
   <#statements#>
}
```

### Delega degli inizializzatori per i tipi classe <a href="#delega-degli-inizializzatori-per-i-tipi-classe" id="delega-degli-inizializzatori-per-i-tipi-classe"></a>

Per semplificare le relazioni tra inizializzatori designati e di convenienza, Swift applica le tre regole seguenti alle chiamate di delega tra inizializzatori:

* **Regola 1**: Un inizializzatore designato deve chiamare un inizializzatore designato della sua superclasse diretta.
* **Regola 2**: Un inizializzatore di convenienza deve chiamare un altro inizializzatore della *stessa* classe.
* **Regola 3**: Un inizializzatore di convenienza deve in ultima analisi chiamare un inizializzatore designato.

Un modo semplice per ricordarlo è:

* Gli inizializzatori designati devono sempre delegare *verso l'alto*.
* Gli inizializzatori di convenienza devono sempre delegare *lateralmente*.

Queste regole sono illustrate nella figura seguente:

![](https://3581893755-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FNzatREGwodw9Z93LQYJb%2Fuploads%2FqM7ydGsJ2xaHzdYz5qKy%2FinitializerDelegation01%402x.png?alt=media)

Qui, la superclasse ha un unico inizializzatore designato e due inizializzatori di convenienza. Un inizializzatore di convenienza chiama un altro inizializzatore di convenienza, che a sua volta chiama l'unico inizializzatore designato. Questo soddisfa le regole 2 e 3 viste sopra. La superclasse non ha a sua volta un'ulteriore superclasse, e quindi la regola 1 non si applica.

La sottoclasse in questa figura ha due inizializzatori designati e un inizializzatore di convenienza. L'inizializzatore di convenienza deve chiamare uno dei due inizializzatori designati, perché può chiamare solo un altro inizializzatore della stessa classe. Questo soddisfa le regole 2 e 3 viste sopra. Entrambi gli inizializzatori designati devono chiamare l'unico inizializzatore designato della superclasse, per soddisfare la regola 1 vista sopra.

{% hint style="info" %}
**Nota:** Queste regole non influiscono sul modo in cui gli utenti delle tue classi *creano* istanze di ciascuna classe. Qualsiasi inizializzatore nel diagramma qui sopra può essere usato per creare un'istanza completamente inizializzata della classe a cui appartiene. Le regole influiscono solo sul modo in cui scrivi l'implementazione degli inizializzatori della classe.
{% endhint %}

La figura seguente mostra una gerarchia di classi più complessa, composta da quattro classi. Illustra come gli inizializzatori designati di questa gerarchia fungano da punti di “imbuto” per l'inizializzazione delle classi, semplificando le interrelazioni tra le classi della catena:

![](https://3581893755-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FNzatREGwodw9Z93LQYJb%2Fuploads%2FWrM5WpI81ggfuwOD2nou%2FinitializerDelegation02%402x.png?alt=media)

### Inizializzazione in due fasi <a href="#inizializzazione-in-due-fasi" id="inizializzazione-in-due-fasi"></a>

In Swift l'inizializzazione delle classi è un processo in due fasi. Nella prima fase, a ciascuna proprietà memorizzata viene assegnato un valore iniziale dalla classe che l'ha introdotta. Una volta determinato lo stato iniziale di ogni proprietà memorizzata, inizia la seconda fase, e a ciascuna classe viene data l'opportunità di personalizzare ulteriormente le proprie proprietà memorizzate prima che la nuova istanza sia considerata pronta all'uso.

L'uso di un processo di inizializzazione in due fasi rende l'inizializzazione sicura, pur dando completa flessibilità a ciascuna classe di una gerarchia di classi. L'inizializzazione in due fasi impedisce che si acceda ai valori delle proprietà prima che siano inizializzati, e impedisce che i valori delle proprietà vengano impostati inaspettatamente a un valore diverso da un altro inizializzatore.

{% hint style="info" %}
**Nota:** Il processo di inizializzazione in due fasi di Swift è simile all'inizializzazione in Objective-C. La differenza principale è che durante la fase 1, Objective-C assegna valori zero o nulli (come `0` o `nil`) a ogni proprietà. Il flusso di inizializzazione di Swift è più flessibile in quanto ti permette di impostare valori iniziali personalizzati, e può gestire tipi per i quali `0` o `nil` non è un valore predefinito valido.
{% endhint %}

Il compilatore di Swift esegue quattro utili controlli di sicurezza per assicurarsi che l'inizializzazione in due fasi venga completata senza errori:

* **Controllo di sicurezza 1**: Un inizializzatore designato deve garantire che tutte le proprietà introdotte dalla sua classe siano inizializzate prima di delegare verso l'alto a un inizializzatore della superclasse.

Come accennato sopra, la memoria di un oggetto è considerata completamente inizializzata solo una volta noto lo stato iniziale di tutte le sue proprietà memorizzate. Affinché questa regola sia soddisfatta, un inizializzatore designato deve assicurarsi che tutte le sue proprietà siano inizializzate prima di passare il controllo lungo la catena.

* **Controllo di sicurezza 2**: Un inizializzatore designato deve delegare verso l'alto a un inizializzatore della superclasse prima di assegnare un valore a una proprietà ereditata. Se non lo fa, il nuovo valore assegnato dall'inizializzatore designato verrà sovrascritto dalla superclasse come parte della sua stessa inizializzazione.
* **Controllo di sicurezza 3**: Un inizializzatore di convenienza deve delegare a un altro inizializzatore prima di assegnare un valore a *qualsiasi* proprietà (comprese le proprietà definite dalla stessa classe). Se non lo fa, il nuovo valore assegnato dall'inizializzatore di convenienza verrà sovrascritto dall'inizializzatore designato della sua stessa classe.
* **Controllo di sicurezza 4**: Un inizializzatore non può chiamare alcun metodo di istanza, leggere i valori di alcuna proprietà di istanza, né fare riferimento a `self` come valore finché la prima fase dell'inizializzazione non è completata.

L'istanza della classe non è pienamente valida finché la prima fase non termina. Si può accedere alle proprietà, e si possono chiamare i metodi, solo una volta che si sa che l'istanza della classe è valida, alla fine della prima fase.

Ecco come si svolge l'inizializzazione in due fasi, in base ai quattro controlli di sicurezza visti sopra:

**Fase 1**

* Su una classe viene chiamato un inizializzatore designato o di convenienza.
* Viene allocata la memoria per una nuova istanza di quella classe. La memoria non è ancora inizializzata.
* Un inizializzatore designato di quella classe conferma che tutte le proprietà memorizzate introdotte da quella classe hanno un valore. La memoria di queste proprietà memorizzate è ora inizializzata.
* L'inizializzatore designato passa il controllo a un inizializzatore della superclasse per svolgere lo stesso compito per le sue proprietà memorizzate.
* Questo prosegue risalendo la catena di ereditarietà delle classi fino a raggiungerne la cima.
* Una volta raggiunta la cima della catena, e dopo che l'ultima classe della catena ha garantito che tutte le sue proprietà memorizzate abbiano un valore, la memoria dell'istanza è considerata completamente inizializzata, e la fase 1 è completata.

**Fase 2**

* Ridiscendendo dalla cima della catena, ogni inizializzatore designato della catena ha la possibilità di personalizzare ulteriormente l'istanza. Gli inizializzatori ora possono accedere a `self` e possono modificarne le proprietà, chiamarne i metodi di istanza e così via.
* Infine, gli eventuali inizializzatori di convenienza della catena hanno la possibilità di personalizzare l'istanza e di lavorare con `self`.

Ecco come appare la fase 1 per una chiamata di inizializzazione su un'ipotetica sottoclasse e superclasse:

![](https://3581893755-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FNzatREGwodw9Z93LQYJb%2Fuploads%2F2BPI19fr6GdFGz1n0Hjr%2FtwoPhaseInitialization01%402x.png?alt=media)

In questo esempio, l'inizializzazione inizia con una chiamata a un inizializzatore di convenienza della sottoclasse. Questo inizializzatore di convenienza non può ancora modificare alcuna proprietà. Delega lateralmente a un inizializzatore designato della stessa classe.

L'inizializzatore designato si assicura che tutte le proprietà della sottoclasse abbiano un valore, secondo il controllo di sicurezza 1. Poi chiama un inizializzatore designato della sua superclasse per continuare l'inizializzazione risalendo la catena.

L'inizializzatore designato della superclasse si assicura che tutte le proprietà della superclasse abbiano un valore. Non ci sono ulteriori superclassi da inizializzare, e quindi non è necessaria alcuna ulteriore delega.

Non appena tutte le proprietà della superclasse hanno un valore iniziale, la sua memoria è considerata completamente inizializzata, e la fase 1 è completata.

Ecco come appare la fase 2 per la stessa chiamata di inizializzazione:

![](https://3581893755-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FNzatREGwodw9Z93LQYJb%2Fuploads%2FSh8jr8i4AF1jZaj7xTyI%2FtwoPhaseInitialization02%402x.png?alt=media)

L'inizializzatore designato della superclasse ha ora l'opportunità di personalizzare ulteriormente l'istanza (anche se non è obbligato a farlo).

Una volta terminato l'inizializzatore designato della superclasse, l'inizializzatore designato della sottoclasse può eseguire ulteriori personalizzazioni (anche in questo caso, non è obbligato a farlo).

Infine, una volta terminato l'inizializzatore designato della sottoclasse, l'inizializzatore di convenienza chiamato inizialmente può eseguire ulteriori personalizzazioni.

### Ereditarietà e override degli inizializzatori <a href="#ereditarieta-e-override-degli-inizializzatori" id="ereditarieta-e-override-degli-inizializzatori"></a>

A differenza delle sottoclassi in Objective-C, le sottoclassi in Swift non ereditano per impostazione predefinita gli inizializzatori della loro superclasse. L'approccio di Swift previene una situazione in cui un semplice inizializzatore di una superclasse venga ereditato da una sottoclasse più specializzata e venga usato per creare una nuova istanza della sottoclasse che non è inizializzata completamente o correttamente.

{% hint style="info" %}
**Nota:** Gli inizializzatori della superclasse *vengono* ereditati in determinate circostanze, ma solo quando farlo è sicuro e appropriato. Per maggiori informazioni, vedi più avanti [Ereditarietà automatica degli inizializzatori](/guida-al-linguaggio/inizializzazione.md#ereditarieta-automatica-degli-inizializzatori).
{% endhint %}

Se vuoi che una sottoclasse personalizzata presenti uno o più degli stessi inizializzatori della sua superclasse, puoi fornire un'implementazione personalizzata di quegli inizializzatori all'interno della sottoclasse.

Quando scrivi un inizializzatore di una sottoclasse che corrisponde a un inizializzatore *designato* della superclasse, stai di fatto fornendo un override di quell'inizializzatore designato. Pertanto, devi scrivere il modificatore `override` prima della definizione dell'inizializzatore della sottoclasse. Questo vale anche se stai sovrascrivendo un inizializzatore predefinito fornito automaticamente, come descritto in [Inizializzatori predefiniti](/guida-al-linguaggio/inizializzazione.md#inizializzatori-predefiniti).

Come per una proprietà, un metodo o un subscript sovrascritti, la presenza del modificatore `override` spinge Swift a verificare che la superclasse abbia un inizializzatore designato corrispondente da sovrascrivere, e convalida che i parametri del tuo inizializzatore di override siano stati specificati come previsto.

{% hint style="info" %}
**Nota:** Scrivi sempre il modificatore `override` quando sovrascrivi un inizializzatore designato della superclasse, anche se l'implementazione dell'inizializzatore nella tua sottoclasse è un inizializzatore di convenienza.
{% endhint %}

Al contrario, se scrivi un inizializzatore di una sottoclasse che corrisponde a un inizializzatore *di convenienza* della superclasse, quell'inizializzatore di convenienza della superclasse non potrà mai essere chiamato direttamente dalla tua sottoclasse, secondo le regole descritte sopra in [Delega degli inizializzatori per i tipi classe](/guida-al-linguaggio/inizializzazione.md#delega-degli-inizializzatori-per-i-tipi-classe). Pertanto, la tua sottoclasse non sta (a rigor di termini) fornendo un override dell'inizializzatore della superclasse. Di conseguenza, non scrivi il modificatore `override` quando fornisci un'implementazione corrispondente di un inizializzatore di convenienza della superclasse.

L'esempio seguente definisce una classe base chiamata `Vehicle`. Questa classe base dichiara una proprietà memorizzata chiamata `numberOfWheels`, con un valore `Int` predefinito di `0`. La proprietà `numberOfWheels` viene usata da una proprietà calcolata chiamata `description` per creare una descrizione `String` delle caratteristiche del veicolo:

```swift
class Vehicle {
    var numberOfWheels = 0
    var description: String {
        return "\(numberOfWheels) wheel(s)"
    }
}
```

La classe `Vehicle` fornisce un valore predefinito per la sua unica proprietà memorizzata, e non fornisce essa stessa alcun inizializzatore personalizzato. Di conseguenza, riceve automaticamente un inizializzatore predefinito, come descritto in [Inizializzatori predefiniti](/guida-al-linguaggio/inizializzazione.md#inizializzatori-predefiniti). L'inizializzatore predefinito (quando disponibile) è sempre un inizializzatore designato per una classe, e può essere usato per creare una nuova istanza di `Vehicle` con un `numberOfWheels` pari a `0`:

```swift
let vehicle = Vehicle()
print("Vehicle: \(vehicle.description)")
// Vehicle: 0 wheel(s)
```

L'esempio successivo definisce una sottoclasse di `Vehicle` chiamata `Bicycle`:

```swift
class Bicycle: Vehicle {
    override init() {
        super.init()
        numberOfWheels = 2
    }
}
```

La sottoclasse `Bicycle` definisce un inizializzatore designato personalizzato, `init()`. Questo inizializzatore designato corrisponde a un inizializzatore designato della superclasse di `Bicycle`, e quindi la versione di questo inizializzatore in `Bicycle` è contrassegnata con il modificatore `override`.

L'inizializzatore `init()` di `Bicycle` inizia chiamando `super.init()`, che chiama l'inizializzatore predefinito della superclasse della classe `Bicycle`, `Vehicle`. Questo garantisce che la proprietà ereditata `numberOfWheels` venga inizializzata da `Vehicle` prima che `Bicycle` abbia l'opportunità di modificare la proprietà. Dopo aver chiamato `super.init()`, il valore originale di `numberOfWheels` viene sostituito con un nuovo valore di `2`.

Se crei un'istanza di `Bicycle`, puoi chiamare la sua proprietà calcolata ereditata `description` per vedere come è stata aggiornata la sua proprietà `numberOfWheels`:

```swift
let bicycle = Bicycle()
print("Bicycle: \(bicycle.description)")
// Bicycle: 2 wheel(s)
```

Se l'inizializzatore di una sottoclasse non esegue alcuna personalizzazione nella fase 2 del processo di inizializzazione, e la superclasse ha un inizializzatore designato sincrono e senza argomenti, puoi omettere la chiamata a `super.init()` dopo aver assegnato i valori a tutte le proprietà memorizzate della sottoclasse. Se l'inizializzatore della superclasse è asincrono, devi scrivere esplicitamente `await super.init()`.

Questo esempio definisce un'altra sottoclasse di `Vehicle`, chiamata `Hoverboard`. Nel suo inizializzatore, la classe `Hoverboard` imposta solo la sua proprietà `color`. Invece di effettuare una chiamata esplicita a `super.init()`, questo inizializzatore si affida a una chiamata implicita all'inizializzatore della sua superclasse per completare il processo.

```swift
class Hoverboard: Vehicle {
    var color: String
    init(color: String) {
        self.color = color
        // super.init() viene chiamato implicitamente qui
    }
    override var description: String {
        return "\(super.description) in a beautiful \(color)"
    }
}
```

Un'istanza di `Hoverboard` usa il numero predefinito di ruote fornito dall'inizializzatore di `Vehicle`.

```swift
let hoverboard = Hoverboard(color: "silver")
print("Hoverboard: \(hoverboard.description)")
// Hoverboard: 0 wheel(s) in a beautiful silver
```

{% hint style="info" %}
**Nota:** Le sottoclassi possono modificare le proprietà variabili ereditate durante l'inizializzazione, ma non possono modificare le proprietà costanti ereditate.
{% endhint %}

### Ereditarietà automatica degli inizializzatori <a href="#ereditarieta-automatica-degli-inizializzatori" id="ereditarieta-automatica-degli-inizializzatori"></a>

Come accennato sopra, le sottoclassi non ereditano per impostazione predefinita gli inizializzatori della loro superclasse. Tuttavia, gli inizializzatori della superclasse *vengono* ereditati automaticamente se sono soddisfatte determinate condizioni. In pratica, ciò significa che in molti scenari comuni non hai bisogno di scrivere override degli inizializzatori, e puoi ereditare gli inizializzatori della tua superclasse con il minimo sforzo ogni volta che farlo è sicuro.

Supponendo che tu fornisca valori predefiniti per tutte le nuove proprietà che introduci in una sottoclasse, si applicano le due regole seguenti:

* **Regola 1**: Se la tua sottoclasse non definisce alcun inizializzatore designato, eredita automaticamente tutti gli inizializzatori designati della sua superclasse.
* **Regola 2**: Se la tua sottoclasse fornisce un'implementazione di *tutti* gli inizializzatori designati della sua superclasse — ereditandoli secondo la regola 1, oppure fornendo un'implementazione personalizzata come parte della sua definizione — allora eredita automaticamente tutti gli inizializzatori di convenienza della superclasse.

Queste regole si applicano anche se la tua sottoclasse aggiunge ulteriori inizializzatori di convenienza.

{% hint style="info" %}
**Nota:** Una sottoclasse può implementare un inizializzatore designato della superclasse come inizializzatore di convenienza della sottoclasse, come parte del soddisfacimento della regola 2.
{% endhint %}

### Inizializzatori designati e di convenienza in azione <a href="#inizializzatori-designati-e-di-convenienza-in-azione" id="inizializzatori-designati-e-di-convenienza-in-azione"></a>

L'esempio seguente mostra in azione inizializzatori designati, inizializzatori di convenienza ed ereditarietà automatica degli inizializzatori. Questo esempio definisce una gerarchia di tre classi chiamate `Food`, `RecipeIngredient` e `ShoppingListItem`, e dimostra come interagiscono i loro inizializzatori.

La classe base della gerarchia si chiama `Food`, ed è una semplice classe che incapsula il nome di un alimento. La classe `Food` introduce un'unica proprietà `String` chiamata `name` e fornisce due inizializzatori per creare istanze di `Food`:

```swift
class Food {
    var name: String
    init(name: String) {
        self.name = name
    }
    convenience init() {
        self.init(name: "[Unnamed]")
    }
}
```

La figura seguente mostra la catena degli inizializzatori della classe `Food`:

![](https://3581893755-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FNzatREGwodw9Z93LQYJb%2Fuploads%2FpJJnyFGVj8V1lK66OBt6%2FinitializersExample01%402x.png?alt=media)

Le classi non hanno un inizializzatore memberwise predefinito, e quindi la classe `Food` fornisce un inizializzatore designato che accetta un unico argomento chiamato `name`. Questo inizializzatore può essere usato per creare una nuova istanza di `Food` con un nome specifico:

```swift
let namedMeat = Food(name: "Bacon")
// il nome di namedMeat è "Bacon"
```

L'inizializzatore `init(name: String)` della classe `Food` è fornito come inizializzatore *designato*, perché garantisce che tutte le proprietà memorizzate di una nuova istanza di `Food` siano completamente inizializzate. La classe `Food` non ha una superclasse, e quindi l'inizializzatore `init(name: String)` non ha bisogno di chiamare `super.init()` per completare la sua inizializzazione.

La classe `Food` fornisce anche un inizializzatore *di convenienza*, `init()`, senza argomenti. L'inizializzatore `init()` fornisce un nome segnaposto predefinito per un nuovo alimento delegando lateralmente all'inizializzatore `init(name: String)` della classe `Food` con un valore `name` pari a `[Unnamed]`:

```swift
let mysteryMeat = Food()
// il nome di mysteryMeat è "[Unnamed]"
```

La seconda classe della gerarchia è una sottoclasse di `Food` chiamata `RecipeIngredient`. La classe `RecipeIngredient` modella un ingrediente di una ricetta di cucina. Introduce una proprietà `Int` chiamata `quantity` (oltre alla proprietà `name` che eredita da `Food`) e definisce due inizializzatori per creare istanze di `RecipeIngredient`:

```swift
class RecipeIngredient: Food {
    var quantity: Int
    init(name: String, quantity: Int) {
        self.quantity = quantity
        super.init(name: name)
    }
    override convenience init(name: String) {
        self.init(name: name, quantity: 1)
    }
}
```

La figura seguente mostra la catena degli inizializzatori della classe `RecipeIngredient`:

![](https://3581893755-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FNzatREGwodw9Z93LQYJb%2Fuploads%2FfBBTp8oYtkRI20scMkwJ%2FinitializersExample02%402x.png?alt=media)

La classe `RecipeIngredient` ha un unico inizializzatore designato, `init(name: String, quantity: Int)`, che può essere usato per popolare tutte le proprietà di una nuova istanza di `RecipeIngredient`. Questo inizializzatore inizia assegnando l'argomento `quantity` ricevuto alla proprietà `quantity`, che è l'unica nuova proprietà introdotta da `RecipeIngredient`. Dopo averlo fatto, l'inizializzatore delega verso l'alto all'inizializzatore `init(name: String)` della classe `Food`. Questo processo soddisfa il controllo di sicurezza 1 di [Inizializzazione in due fasi](/guida-al-linguaggio/inizializzazione.md#inizializzazione-in-due-fasi) visto sopra.

`RecipeIngredient` definisce anche un inizializzatore di convenienza, `init(name: String)`, che viene usato per creare un'istanza di `RecipeIngredient` solo tramite il nome. Questo inizializzatore di convenienza presuppone una quantità pari a `1` per qualsiasi istanza di `RecipeIngredient` creata senza una quantità esplicita. La definizione di questo inizializzatore di convenienza rende le istanze di `RecipeIngredient` più rapide e comode da creare, ed evita duplicazioni di codice quando si creano diverse istanze di `RecipeIngredient` con quantità pari a uno. Questo inizializzatore di convenienza delega semplicemente lateralmente all'inizializzatore designato della classe, passando un valore `quantity` pari a `1`.

L'inizializzatore di convenienza `init(name: String)` fornito da `RecipeIngredient` accetta gli stessi parametri dell'inizializzatore *designato* `init(name: String)` di `Food`. Poiché questo inizializzatore di convenienza sovrascrive un inizializzatore designato della sua superclasse, deve essere contrassegnato con il modificatore `override` (come descritto in [Ereditarietà e override degli inizializzatori](/guida-al-linguaggio/inizializzazione.md#ereditarieta-e-override-degli-inizializzatori)).

Anche se `RecipeIngredient` fornisce l'inizializzatore `init(name: String)` come inizializzatore di convenienza, `RecipeIngredient` ha comunque fornito un'implementazione di tutti gli inizializzatori designati della sua superclasse. Pertanto, `RecipeIngredient` eredita automaticamente anche tutti gli inizializzatori di convenienza della sua superclasse.

In questo esempio, la superclasse di `RecipeIngredient` è `Food`, che ha un unico inizializzatore di convenienza chiamato `init()`. Questo inizializzatore viene quindi ereditato da `RecipeIngredient`. La versione ereditata di `init()` funziona esattamente nello stesso modo della versione di `Food`, tranne per il fatto che delega alla versione di `init(name: String)` di `RecipeIngredient` anziché a quella di `Food`.

Tutti e tre questi inizializzatori possono essere usati per creare nuove istanze di `RecipeIngredient`:

```swift
let oneMysteryItem = RecipeIngredient()
let oneBacon = RecipeIngredient(name: "Bacon")
let sixEggs = RecipeIngredient(name: "Eggs", quantity: 6)
```

La terza e ultima classe della gerarchia è una sottoclasse di `RecipeIngredient` chiamata `ShoppingListItem`. La classe `ShoppingListItem` modella un ingrediente di una ricetta così come compare in una lista della spesa.

Ogni articolo della lista della spesa parte come “non acquistato”. Per rappresentare questo fatto, `ShoppingListItem` introduce una proprietà booleana chiamata `purchased`, con un valore predefinito di `false`. `ShoppingListItem` aggiunge anche una proprietà calcolata `description`, che fornisce una descrizione testuale di un'istanza di `ShoppingListItem`:

```swift
class ShoppingListItem: RecipeIngredient {
    var purchased = false
    var description: String {
        var output = "\(quantity) x \(name)"
        output += purchased ? " ✔" : " ✘"
        return output
    }
}
```

{% hint style="info" %}
**Nota:** `ShoppingListItem` non definisce un inizializzatore per fornire un valore iniziale a `purchased`, perché gli articoli di una lista della spesa (così come sono modellati qui) partono sempre come non acquistati.
{% endhint %}

Poiché fornisce un valore predefinito per tutte le proprietà che introduce e non definisce essa stessa alcun inizializzatore, `ShoppingListItem` eredita automaticamente *tutti* gli inizializzatori designati e di convenienza della sua superclasse.

La figura seguente mostra la catena complessiva degli inizializzatori per tutte e tre le classi:

![](https://3581893755-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FNzatREGwodw9Z93LQYJb%2Fuploads%2FTcbVPSD7Ux0nwm8S4dzx%2FinitializersExample03%402x.png?alt=media)

Puoi usare tutti e tre gli inizializzatori ereditati per creare una nuova istanza di `ShoppingListItem`:

```swift
var breakfastList = [
    ShoppingListItem(),
    ShoppingListItem(name: "Bacon"),
    ShoppingListItem(name: "Eggs", quantity: 6),
]
breakfastList[0].name = "Orange juice"
breakfastList[0].purchased = true
for item in breakfastList {
    print(item.description)
}
// 1 x Orange juice ✔
// 1 x Bacon ✘
// 6 x Eggs ✘
```

Qui, viene creato un nuovo array chiamato `breakfastList` a partire da un letterale array contenente tre nuove istanze di `ShoppingListItem`. Il tipo dell'array viene inferito come `[ShoppingListItem]`. Dopo la creazione dell'array, il nome dello `ShoppingListItem` all'inizio dell'array viene cambiato da `"[Unnamed]"` a `"Orange juice"` e viene contrassegnato come acquistato. Stampare la descrizione di ciascun elemento dell'array mostra che i loro stati predefiniti sono stati impostati come previsto.

## Inizializzatori failable <a href="#inizializzatori-failable" id="inizializzatori-failable"></a>

A volte è utile definire una classe, una struttura o un'enumerazione la cui inizializzazione può fallire. Questo fallimento potrebbe essere causato da valori non validi dei parametri di inizializzazione, dall'assenza di una risorsa esterna necessaria, o da qualche altra condizione che impedisce all'inizializzazione di avere successo.

Per far fronte a condizioni di inizializzazione che possono fallire, definisci uno o più inizializzatori failable come parte della definizione di una classe, una struttura o un'enumerazione. Scrivi un inizializzatore failable collocando un punto interrogativo dopo la parola chiave `init` (`init?`).

{% hint style="info" %}
**Nota:** Non puoi definire un inizializzatore failable e uno non failable con gli stessi tipi e nomi dei parametri.
{% endhint %}

Un inizializzatore failable crea un valore *opzionale* del tipo che inizializza. Scrivi `return nil` all'interno di un inizializzatore failable per indicare un punto in cui può essere attivato il fallimento dell'inizializzazione.

{% hint style="info" %}
**Nota:** A rigor di termini, gli inizializzatori non restituiscono un valore. Il loro ruolo è piuttosto garantire che `self` sia inizializzato completamente e correttamente entro la fine dell'inizializzazione. Sebbene tu scriva `return nil` per attivare un fallimento dell'inizializzazione, non usi la parola chiave `return` per indicare il successo dell'inizializzazione.
{% endhint %}

Per esempio, gli inizializzatori failable sono implementati per le conversioni tra tipi numerici. Per garantire che la conversione tra tipi numerici mantenga esattamente il valore, usa l'inizializzatore `init(exactly:)`. Se la conversione di tipo non può mantenere il valore, l'inizializzatore fallisce.

```swift
let wholeNumber: Double = 12345.0
let pi = 3.14159

if let valueMaintained = Int(exactly: wholeNumber) {
    print("\(wholeNumber) conversion to Int maintains value of \(valueMaintained)")
}
// Stampa "12345.0 conversion to Int maintains value of 12345".

let valueChanged = Int(exactly: pi)
// valueChanged è di tipo Int?, non Int

if valueChanged == nil {
    print("\(pi) conversion to Int doesn't maintain value")
}
// Stampa "3.14159 conversion to Int doesn't maintain value".
```

L'esempio seguente definisce una struttura chiamata `Animal`, con una proprietà `String` costante chiamata `species`. La struttura `Animal` definisce anche un inizializzatore failable con un unico parametro chiamato `species`. Questo inizializzatore verifica se il valore `species` passato all'inizializzatore è una stringa vuota. Se viene trovata una stringa vuota, viene attivato un fallimento dell'inizializzazione. Altrimenti, il valore della proprietà `species` viene impostato, e l'inizializzazione ha successo:

```swift
struct Animal {
    let species: String
    init?(species: String) {
        if species.isEmpty { return nil }
        self.species = species
    }
}
```

Puoi usare questo inizializzatore failable per provare a inizializzare una nuova istanza di `Animal` e per verificare se l'inizializzazione ha avuto successo:

```swift
let someCreature = Animal(species: "Giraffe")
// someCreature è di tipo Animal?, non Animal

if let giraffe = someCreature {
    print("An animal was initialized with a species of \(giraffe.species)")
}
// Stampa "An animal was initialized with a species of Giraffe".
```

Se passi un valore stringa vuota al parametro `species` dell'inizializzatore failable, l'inizializzatore attiva un fallimento dell'inizializzazione:

```swift
let anonymousCreature = Animal(species: "")
// anonymousCreature è di tipo Animal?, non Animal

if anonymousCreature == nil {
    print("The anonymous creature couldn't be initialized")
}
// Stampa "The anonymous creature couldn't be initialized".
```

{% hint style="info" %}
**Nota:** Verificare un valore stringa vuota (come `""` anziché `"Giraffe"`) non è la stessa cosa che verificare `nil` per indicare l'assenza di un valore `String` *opzionale*. Nell'esempio qui sopra, una stringa vuota (`""`) è una `String` valida e non opzionale. Tuttavia, non è appropriato che un animale abbia una stringa vuota come valore della sua proprietà `species`. Per modellare questa restrizione, l'inizializzatore failable attiva un fallimento dell'inizializzazione se viene trovata una stringa vuota.
{% endhint %}

### Inizializzatori failable per le enumerazioni <a href="#inizializzatori-failable-per-le-enumerazioni" id="inizializzatori-failable-per-le-enumerazioni"></a>

Puoi usare un inizializzatore failable per selezionare un caso di enumerazione appropriato in base a uno o più parametri. L'inizializzatore può quindi fallire se i parametri forniti non corrispondono a un caso di enumerazione appropriato.

L'esempio seguente definisce un'enumerazione chiamata `TemperatureUnit`, con tre possibili stati (`kelvin`, `celsius` e `fahrenheit`). Un inizializzatore failable viene usato per trovare un caso di enumerazione appropriato per un valore `Character` che rappresenta un simbolo di temperatura:

```swift
enum TemperatureUnit {
    case kelvin, celsius, fahrenheit
    init?(symbol: Character) {
        switch symbol {
        case "K":
            self = .kelvin
        case "C":
            self = .celsius
        case "F":
            self = .fahrenheit
        default:
            return nil
        }
    }
}
```

Puoi usare questo inizializzatore failable per scegliere un caso di enumerazione appropriato per i tre possibili stati e per far fallire l'inizializzazione se il parametro non corrisponde a uno di questi stati:

```swift
let fahrenheitUnit = TemperatureUnit(symbol: "F")
if fahrenheitUnit != nil {
    print("This is a defined temperature unit, so initialization succeeded.")
}
// Stampa "This is a defined temperature unit, so initialization succeeded."

let unknownUnit = TemperatureUnit(symbol: "X")
if unknownUnit == nil {
    print("This isn't a defined temperature unit, so initialization failed.")
}
// Stampa "This isn't a defined temperature unit, so initialization failed."
```

### Inizializzatori failable per le enumerazioni con valori grezzi <a href="#inizializzatori-failable-per-le-enumerazioni-con-valori-grezzi" id="inizializzatori-failable-per-le-enumerazioni-con-valori-grezzi"></a>

Le enumerazioni con valori grezzi ricevono automaticamente un inizializzatore failable, `init?(rawValue:)`, che accetta un parametro chiamato `rawValue` del tipo di valore grezzo appropriato e seleziona un caso di enumerazione corrispondente se ne viene trovato uno, oppure attiva un fallimento dell'inizializzazione se non esiste alcun valore corrispondente.

Puoi riscrivere l'esempio `TemperatureUnit` visto sopra per usare valori grezzi di tipo `Character` e avvalerti dell'inizializzatore `init?(rawValue:)`:

```swift
enum TemperatureUnit: Character {
    case kelvin = "K", celsius = "C", fahrenheit = "F"
}

let fahrenheitUnit = TemperatureUnit(rawValue: "F")
if fahrenheitUnit != nil {
    print("This is a defined temperature unit, so initialization succeeded.")
}
// Stampa "This is a defined temperature unit, so initialization succeeded."

let unknownUnit = TemperatureUnit(rawValue: "X")
if unknownUnit == nil {
    print("This isn't a defined temperature unit, so initialization failed.")
}
// Stampa "This isn't a defined temperature unit, so initialization failed."
```

### Propagazione del fallimento dell'inizializzazione <a href="#propagazione-del-fallimento-dellinizializzazione" id="propagazione-del-fallimento-dellinizializzazione"></a>

Un inizializzatore failable di una classe, una struttura o un'enumerazione può delegare lateralmente a un altro inizializzatore failable della stessa classe, struttura o enumerazione. Analogamente, un inizializzatore failable di una sottoclasse può delegare verso l'alto a un inizializzatore failable della superclasse.

In entrambi i casi, se deleghi a un altro inizializzatore che fa fallire l'inizializzazione, l'intero processo di inizializzazione fallisce immediatamente, e non viene eseguito alcun ulteriore codice di inizializzazione.

{% hint style="info" %}
**Nota:** Un inizializzatore failable può anche delegare a un inizializzatore non failable. Usa questo approccio se hai bisogno di aggiungere un potenziale stato di fallimento a un processo di inizializzazione esistente che altrimenti non fallisce.
{% endhint %}

L'esempio seguente definisce una sottoclasse di `Product` chiamata `CartItem`. La classe `CartItem` modella un articolo in un carrello della spesa online. `CartItem` introduce una proprietà costante memorizzata chiamata `quantity` e garantisce che questa proprietà abbia sempre un valore pari ad almeno `1`:

```swift
class Product {
    let name: String
    init?(name: String) {
        if name.isEmpty { return nil }
        self.name = name
    }
}

class CartItem: Product {
    let quantity: Int
    init?(name: String, quantity: Int) {
        if quantity < 1 { return nil }
        self.quantity = quantity
        super.init(name: name)
    }
}
```

L'inizializzatore failable di `CartItem` inizia verificando di aver ricevuto un valore `quantity` pari a `1` o superiore. Se `quantity` non è valida, l'intero processo di inizializzazione fallisce immediatamente e non viene eseguito alcun ulteriore codice di inizializzazione. Allo stesso modo, l'inizializzatore failable di `Product` verifica il valore di `name`, e il processo di inizializzazione fallisce immediatamente se `name` è la stringa vuota.

Se crei un'istanza di `CartItem` con un nome non vuoto e una quantità pari a `1` o superiore, l'inizializzazione ha successo:

```swift
if let twoSocks = CartItem(name: "sock", quantity: 2) {
    print("Item: \(twoSocks.name), quantity: \(twoSocks.quantity)")
}
// Stampa "Item: sock, quantity: 2".
```

Se provi a creare un'istanza di `CartItem` con un valore `quantity` pari a `0`, l'inizializzatore di `CartItem` fa fallire l'inizializzazione:

```swift
if let zeroShirts = CartItem(name: "shirt", quantity: 0) {
    print("Item: \(zeroShirts.name), quantity: \(zeroShirts.quantity)")
} else {
    print("Unable to initialize zero shirts")
}
// Stampa "Unable to initialize zero shirts".
```

Analogamente, se provi a creare un'istanza di `CartItem` con un valore `name` vuoto, l'inizializzatore della superclasse `Product` fa fallire l'inizializzazione:

```swift
if let oneUnnamed = CartItem(name: "", quantity: 1) {
    print("Item: \(oneUnnamed.name), quantity: \(oneUnnamed.quantity)")
} else {
    print("Unable to initialize one unnamed product")
}
// Stampa "Unable to initialize one unnamed product".
```

### Override di un inizializzatore failable <a href="#override-di-un-inizializzatore-failable" id="override-di-un-inizializzatore-failable"></a>

Puoi sovrascrivere un inizializzatore failable della superclasse in una sottoclasse, proprio come qualsiasi altro inizializzatore. In alternativa, puoi sovrascrivere un inizializzatore failable della superclasse con un inizializzatore *non failable* della sottoclasse. Questo ti permette di definire una sottoclasse la cui inizializzazione non può fallire, anche se all'inizializzazione della superclasse è consentito fallire.

Nota che se sovrascrivi un inizializzatore failable della superclasse con un inizializzatore non failable della sottoclasse, l'unico modo per delegare verso l'alto all'inizializzatore della superclasse è forzare l'unwrapping del risultato dell'inizializzatore failable della superclasse.

{% hint style="info" %}
**Nota:** Puoi sovrascrivere un inizializzatore failable con un inizializzatore non failable ma non viceversa.
{% endhint %}

L'esempio seguente definisce una classe chiamata `Document`. Questa classe modella un documento che può essere inizializzato con una proprietà `name` che è un valore stringa non vuoto oppure `nil`, ma non può essere una stringa vuota:

```swift
class Document {
    var name: String?
    // questo inizializzatore crea un documento con un valore name nil
    init() {}
    // questo inizializzatore crea un documento con un valore name non vuoto
    init?(name: String) {
        if name.isEmpty { return nil }
        self.name = name
    }
}
```

L'esempio successivo definisce una sottoclasse di `Document` chiamata `AutomaticallyNamedDocument`. La sottoclasse `AutomaticallyNamedDocument` sovrascrive entrambi gli inizializzatori designati introdotti da `Document`. Questi override garantiscono che un'istanza di `AutomaticallyNamedDocument` abbia un valore `name` iniziale pari a `"[Untitled]"` se l'istanza viene inizializzata senza un nome, o se all'inizializzatore `init(name:)` viene passata una stringa vuota:

```swift
class AutomaticallyNamedDocument: Document {
    override init() {
        super.init()
        self.name = "[Untitled]"
    }
    override init(name: String) {
        super.init()
        if name.isEmpty {
            self.name = "[Untitled]"
        } else {
            self.name = name
        }
    }
}
```

`AutomaticallyNamedDocument` sovrascrive l'inizializzatore failable `init?(name:)` della sua superclasse con un inizializzatore non failable `init(name:)`. Poiché `AutomaticallyNamedDocument` gestisce il caso della stringa vuota in modo diverso dalla sua superclasse, il suo inizializzatore non ha bisogno di fallire, e quindi fornisce invece una versione non failable dell'inizializzatore.

Puoi usare l'unwrapping forzato in un inizializzatore per chiamare un inizializzatore failable della superclasse come parte dell'implementazione dell'inizializzatore non failable di una sottoclasse. Per esempio, la sottoclasse `UntitledDocument` seguente si chiama sempre `"[Untitled]"`, e usa l'inizializzatore failable `init(name:)` della sua superclasse durante l'inizializzazione.

```swift
class UntitledDocument: Document {
    override init() {
        super.init(name: "[Untitled]")!
    }
}
```

In questo caso, se l'inizializzatore `init(name:)` della superclasse venisse mai chiamato con una stringa vuota come nome, l'operazione di unwrapping forzato produrrebbe un errore in fase di esecuzione. Tuttavia, poiché viene chiamato con un letterale stringa, puoi vedere che l'inizializzatore non fallirà, quindi in questo caso non può verificarsi alcun errore in fase di esecuzione.

### L'inizializzatore failable init! <a href="#linizializzatore-failable-init" id="linizializzatore-failable-init"></a>

Di solito definisci un inizializzatore failable che crea un'istanza opzionale del tipo appropriato collocando un punto interrogativo dopo la parola chiave `init` (`init?`). In alternativa, puoi definire un inizializzatore failable che crea un'istanza opzionale con unwrapping implicito del tipo appropriato. Per farlo, colloca un punto esclamativo dopo la parola chiave `init` (`init!`) invece di un punto interrogativo.

Puoi delegare da `init?` a `init!` e viceversa, e puoi sovrascrivere `init?` con `init!` e viceversa. Puoi anche delegare da `init` a `init!`, anche se così facendo attiverai un'asserzione se l'inizializzatore `init!` fa fallire l'inizializzazione.

## Inizializzatori required <a href="#inizializzatori-required" id="inizializzatori-required"></a>

Scrivi il modificatore `required` prima della definizione dell'inizializzatore di una classe per indicare che ogni sottoclasse della classe deve implementare quell'inizializzatore:

```swift
class SomeClass {
    required init() {
        // qui va l'implementazione dell'inizializzatore
    }
}
```

Devi scrivere il modificatore `required` anche prima di ogni implementazione in una sottoclasse di un inizializzatore required, per indicare che il requisito dell'inizializzatore si applica alle ulteriori sottoclassi della catena. Non scrivi il modificatore `override` quando sovrascrivi un inizializzatore designato required:

```swift
class SomeSubclass: SomeClass {
    required init() {
        // qui va l'implementazione nella sottoclasse dell'inizializzatore required
    }
}
```

{% hint style="info" %}
**Nota:** Non devi fornire un'implementazione esplicita di un inizializzatore required se puoi soddisfare il requisito con un inizializzatore ereditato.
{% endhint %}

## Impostare il valore predefinito di una proprietà con una closure o una funzione <a href="#impostare-il-valore-predefinito-di-una-proprieta-con-una-closure-o-una-funzione" id="impostare-il-valore-predefinito-di-una-proprieta-con-una-closure-o-una-funzione"></a>

Se il valore predefinito di una proprietà memorizzata richiede qualche personalizzazione o configurazione, puoi usare una closure o una funzione globale per fornire un valore predefinito personalizzato per quella proprietà. Ogni volta che viene inizializzata una nuova istanza del tipo a cui appartiene la proprietà, la closure o la funzione viene chiamata, e il suo valore di ritorno viene assegnato come valore predefinito della proprietà.

Questo tipo di closure o funzioni tipicamente crea un valore temporaneo dello stesso tipo della proprietà, adatta quel valore per rappresentare lo stato iniziale desiderato, e poi restituisce quel valore temporaneo da usare come valore predefinito della proprietà.

Ecco uno schema di base di come si può usare una closure per fornire il valore predefinito di una proprietà:

```swift
class SomeClass {
    let someProperty: SomeType = {
        // crea un valore predefinito per someProperty all'interno di questa closure
        // someValue deve essere dello stesso tipo di SomeType
        return someValue
    }()
}
```

Nota che la parentesi graffa di chiusura della closure è seguita da una coppia vuota di parentesi tonde. Questo dice a Swift di eseguire immediatamente la closure. Se ometti queste parentesi, stai cercando di assegnare alla proprietà la closure stessa, e non il valore di ritorno della closure.

{% hint style="info" %}
**Nota:** Se usi una closure per inizializzare una proprietà, ricorda che il resto dell'istanza non è ancora stato inizializzato nel momento in cui la closure viene eseguita. Ciò significa che non puoi accedere ai valori di altre proprietà dall'interno della tua closure, anche se quelle proprietà hanno valori predefiniti. Non puoi nemmeno usare la proprietà implicita `self`, né chiamare alcuno dei metodi dell'istanza.
{% endhint %}

L'esempio seguente definisce una struttura chiamata `Chessboard`, che modella una scacchiera per il gioco degli scacchi. Gli scacchi si giocano su una scacchiera 8 x 8, con caselle alternate nere e bianche.

![](https://3581893755-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FNzatREGwodw9Z93LQYJb%2Fuploads%2FWa66B8EJIrNgsKEUuUhR%2FchessBoard%402x.png?alt=media)

Per rappresentare questa scacchiera, la struttura `Chessboard` ha un'unica proprietà chiamata `boardColors`, che è un array di 64 valori `Bool`. Un valore `true` nell'array rappresenta una casella nera e un valore `false` rappresenta una casella bianca. Il primo elemento dell'array rappresenta la casella in alto a sinistra della scacchiera e l'ultimo elemento dell'array rappresenta la casella in basso a destra della scacchiera.

L'array `boardColors` viene inizializzato con una closure per impostare i suoi valori di colore:

```swift
struct Chessboard {
    let boardColors: [Bool] = {
        var temporaryBoard: [Bool] = []
        var isBlack = false
        for i in 1...8 {
            for j in 1...8 {
                temporaryBoard.append(isBlack)
                isBlack = !isBlack
            }
            isBlack = !isBlack
        }
        return temporaryBoard
    }()
    func squareIsBlackAt(row: Int, column: Int) -> Bool {
        return boardColors[(row * 8) + column]
    }
}
```

Ogni volta che viene creata una nuova istanza di `Chessboard`, la closure viene eseguita, e il valore predefinito di `boardColors` viene calcolato e restituito. La closure dell'esempio qui sopra calcola e imposta il colore appropriato per ciascuna casella della scacchiera in un array temporaneo chiamato `temporaryBoard`, e restituisce questo array temporaneo come valore di ritorno della closure una volta completata la sua configurazione. Il valore array restituito viene memorizzato in `boardColors` e può essere interrogato con la funzione di utilità `squareIsBlackAt(row:column:)`:

```swift
let board = Chessboard()
print(board.squareIsBlackAt(row: 0, column: 1))
// Stampa "true".
print(board.squareIsBlackAt(row: 7, column: 7))
// Stampa "false".
```
