> 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/optional-chaining.md).

# Optional chaining

Accedi ai membri di un valore opzionale senza farne l'unwrapping.

L'*optional chaining* (concatenamento opzionale) è un processo per interrogare e chiamare proprietà, metodi e subscript su un opzionale che potrebbe essere attualmente `nil`. Se l'opzionale contiene un valore, la chiamata alla proprietà, al metodo o al subscript ha successo; se l'opzionale è `nil`, la chiamata alla proprietà, al metodo o al subscript restituisce `nil`. Più interrogazioni possono essere concatenate, e l'intera catena fallisce in modo controllato se un qualsiasi anello della catena è `nil`.

{% hint style="info" %}
**Nota:** L'optional chaining in Swift è simile all'invio di messaggi a `nil` in Objective-C, ma in un modo che funziona per qualsiasi tipo e che può essere verificato per stabilirne il successo o il fallimento.
{% endhint %}

## L'optional chaining come alternativa all'unwrapping forzato <a href="#loptional-chaining-come-alternativa-allunwrapping-forzato" id="loptional-chaining-come-alternativa-allunwrapping-forzato"></a>

Specifichi l'optional chaining collocando un punto interrogativo (`?`) dopo il valore opzionale su cui desideri chiamare una proprietà, un metodo o un subscript se l'opzionale è diverso da `nil`. Questo è molto simile a collocare un punto esclamativo (`!`) dopo un valore opzionale per forzare l'unwrapping del suo valore. La differenza principale è che l'optional chaining fallisce in modo controllato quando l'opzionale è `nil`, mentre l'unwrapping forzato attiva un errore in fase di esecuzione quando l'opzionale è `nil`.

Per riflettere il fatto che l'optional chaining può essere chiamato su un valore `nil`, il risultato di una chiamata in optional chaining è sempre un valore opzionale, anche se la proprietà, il metodo o il subscript che stai interrogando restituisce un valore non opzionale. Puoi usare questo valore di ritorno opzionale per verificare se la chiamata in optional chaining ha avuto successo (l'opzionale restituito contiene un valore), oppure non ha avuto successo a causa di un valore `nil` nella catena (il valore opzionale restituito è `nil`).

Nello specifico, il risultato di una chiamata in optional chaining è dello stesso tipo del valore di ritorno atteso, ma racchiuso in un opzionale. Una proprietà che normalmente restituisce un `Int` restituirà un `Int?` quando vi si accede tramite optional chaining.

I prossimi frammenti di codice dimostrano come l'optional chaining differisca dall'unwrapping forzato e ti permetta di verificarne il successo.

Per prima cosa, vengono definite due classi chiamate `Person` e `Residence`:

```swift
class Person {
    var residence: Residence?
}

class Residence {
    var numberOfRooms = 1
}
```

Le istanze di `Residence` hanno un'unica proprietà `Int` chiamata `numberOfRooms`, con un valore predefinito di `1`. Le istanze di `Person` hanno una proprietà opzionale `residence` di tipo `Residence?`.

Se crei una nuova istanza di `Person`, la sua proprietà `residence` viene inizializzata per impostazione predefinita a `nil`, in virtù del fatto che è opzionale. Nel codice seguente, `john` ha una proprietà `residence` con valore `nil`:

```swift
let john = Person()
```

Se provi ad accedere alla proprietà `numberOfRooms` della `residence` di questa persona, collocando un punto esclamativo dopo `residence` per forzare l'unwrapping del suo valore, attivi un errore in fase di esecuzione, perché non c'è alcun valore `residence` di cui fare l'unwrapping:

```swift
let roomCount = john.residence!.numberOfRooms
// questo attiva un errore in fase di esecuzione
```

Il codice qui sopra ha successo quando `john.residence` ha un valore diverso da `nil` e imposterà `roomCount` a un valore `Int` contenente il numero appropriato di stanze. Tuttavia, questo codice attiva sempre un errore in fase di esecuzione quando `residence` è `nil`, come illustrato sopra.

L'optional chaining fornisce un modo alternativo per accedere al valore di `numberOfRooms`. Per usare l'optional chaining, usa un punto interrogativo al posto del punto esclamativo:

```swift
if let roomCount = john.residence?.numberOfRooms {
    print("John's residence has \(roomCount) room(s).")
} else {
    print("Unable to retrieve the number of rooms.")
}
// Stampa "Unable to retrieve the number of rooms."
```

Questo dice a Swift di “concatenare” sulla proprietà opzionale `residence` e di recuperare il valore di `numberOfRooms` se `residence` esiste.

Poiché il tentativo di accedere a `numberOfRooms` può potenzialmente fallire, il tentativo di optional chaining restituisce un valore di tipo `Int?`, ovvero “`Int` opzionale”. Quando `residence` è `nil`, come nell'esempio qui sopra, anche questo `Int` opzionale sarà `nil`, per riflettere il fatto che non è stato possibile accedere a `numberOfRooms`. Si accede all'`Int` opzionale tramite optional binding per fare l'unwrapping dell'intero e assegnare il valore non opzionale alla costante `roomCount`.

Nota che questo è vero anche se `numberOfRooms` è un `Int` non opzionale. Il fatto che venga interrogato tramite una catena opzionale significa che la chiamata a `numberOfRooms` restituirà sempre un `Int?` anziché un `Int`.

Puoi assegnare un'istanza di `Residence` a `john.residence`, in modo che non abbia più un valore `nil`:

```swift
john.residence = Residence()
```

`john.residence` ora contiene un'effettiva istanza di `Residence`, anziché `nil`. Se provi ad accedere a `numberOfRooms` con lo stesso optional chaining di prima, ora restituirà un `Int?` che contiene il valore predefinito di `numberOfRooms`, ovvero `1`:

```swift
if let roomCount = john.residence?.numberOfRooms {
    print("John's residence has \(roomCount) room(s).")
} else {
    print("Unable to retrieve the number of rooms.")
}
// Stampa "John's residence has 1 room(s)."
```

## Definire classi modello per l'optional chaining <a href="#definire-classi-modello-per-loptional-chaining" id="definire-classi-modello-per-loptional-chaining"></a>

Puoi usare l'optional chaining con chiamate a proprietà, metodi e subscript che si trovano a più di un livello di profondità. Questo ti permette di scendere nelle sotto-proprietà all'interno di modelli complessi di tipi correlati, e di verificare se è possibile accedere a proprietà, metodi e subscript su quelle sotto-proprietà.

I frammenti di codice seguenti definiscono quattro classi modello da usare in diversi esempi successivi, compresi esempi di optional chaining su più livelli. Queste classi ampliano il modello `Person` e `Residence` visto sopra aggiungendo le classi `Room` e `Address`, con proprietà, metodi e subscript associati.

La classe `Person` è definita nello stesso modo di prima:

```swift
class Person {
    var residence: Residence?
}
```

La classe `Residence` è più complessa di prima. Questa volta, la classe `Residence` definisce una proprietà variabile chiamata `rooms`, che viene inizializzata con un array vuoto di tipo `[Room]`:

```swift
class Residence {
    var rooms: [Room] = []
    var numberOfRooms: Int {
        return rooms.count
    }
    subscript(i: Int) -> Room {
        get {
            return rooms[i]
        }
        set {
            rooms[i] = newValue
        }
    }
    func printNumberOfRooms() {
        print("The number of rooms is \(numberOfRooms)")
    }
    var address: Address?
}
```

Poiché questa versione di `Residence` memorizza un array di istanze di `Room`, la sua proprietà `numberOfRooms` è implementata come proprietà calcolata, non come proprietà memorizzata. La proprietà calcolata `numberOfRooms` restituisce semplicemente il valore della proprietà `count` dell'array `rooms`.

Come scorciatoia per accedere al suo array `rooms`, questa versione di `Residence` fornisce un subscript di lettura e scrittura che fornisce l'accesso alla stanza all'indice richiesto nell'array `rooms`.

Questa versione di `Residence` fornisce anche un metodo chiamato `printNumberOfRooms`, che si limita a stampare il numero di stanze della residenza.

Infine, `Residence` definisce una proprietà opzionale chiamata `address`, di tipo `Address?`. Il tipo classe `Address` per questa proprietà è definito più avanti.

La classe `Room` usata per l'array `rooms` è una semplice classe con una proprietà chiamata `name`, e un inizializzatore per impostare quella proprietà a un nome di stanza adeguato:

```swift
class Room {
    let name: String
    init(name: String) { self.name = name }
}
```

L'ultima classe di questo modello si chiama `Address`. Questa classe ha tre proprietà opzionali di tipo `String?`. Le prime due proprietà, `buildingName` e `buildingNumber`, sono modi alternativi di identificare un particolare edificio come parte di un indirizzo. La terza proprietà, `street`, è usata per indicare la via di quell'indirizzo:

```swift
class Address {
    var buildingName: String?
    var buildingNumber: String?
    var street: String?
    func buildingIdentifier() -> String? {
        if let buildingNumber = buildingNumber, let street = street {
            return "\(buildingNumber) \(street)"
        } else if buildingName != nil {
            return buildingName
        } else {
            return nil
        }
    }
}
```

La classe `Address` fornisce anche un metodo chiamato `buildingIdentifier()`, che ha un tipo di ritorno `String?`. Questo metodo verifica le proprietà dell'indirizzo e restituisce `buildingName` se ha un valore, oppure `buildingNumber` concatenato con `street` se entrambi hanno un valore, oppure `nil` in caso contrario.

## Accedere alle proprietà tramite optional chaining <a href="#accedere-alle-proprieta-tramite-optional-chaining" id="accedere-alle-proprieta-tramite-optional-chaining"></a>

Come dimostrato in [L'optional chaining come alternativa all'unwrapping forzato](/guida-al-linguaggio/optional-chaining.md#loptional-chaining-come-alternativa-allunwrapping-forzato), puoi usare l'optional chaining per accedere a una proprietà di un valore opzionale, e per verificare se quell'accesso alla proprietà ha successo.

Usa le classi definite sopra per creare una nuova istanza di `Person`, e prova ad accedere alla sua proprietà `numberOfRooms` come prima:

```swift
let john = Person()
if let roomCount = john.residence?.numberOfRooms {
    print("John's residence has \(roomCount) room(s).")
} else {
    print("Unable to retrieve the number of rooms.")
}
// Stampa "Unable to retrieve the number of rooms."
```

Poiché `john.residence` è `nil`, questa chiamata in optional chaining fallisce nello stesso modo di prima.

Puoi anche tentare di impostare il valore di una proprietà tramite optional chaining:

```swift
let someAddress = Address()
someAddress.buildingNumber = "29"
someAddress.street = "Acacia Road"
john.residence?.address = someAddress
```

In questo esempio, il tentativo di impostare la proprietà `address` di `john.residence` fallirà, perché `john.residence` è attualmente `nil`.

L'assegnamento fa parte dell'optional chaining, il che significa che nessuna parte del codice sul lato destro dell'operatore `=` viene valutata. Nell'esempio precedente, non è facile vedere che `someAddress` non viene mai valutato, perché accedere a una costante non ha alcun effetto collaterale. Il listato seguente esegue lo stesso assegnamento, ma usa una funzione per creare l'indirizzo. La funzione stampa "Function was called" prima di restituire un valore, il che ti permette di vedere se il lato destro dell'operatore `=` è stato valutato.

```swift
func createAddress() -> Address {
    print("Function was called.")

    let someAddress = Address()
    someAddress.buildingNumber = "29"
    someAddress.street = "Acacia Road"

    return someAddress
}
john.residence?.address = createAddress()
```

Puoi capire che la funzione `createAddress()` non viene chiamata, perché non viene stampato nulla.

## Chiamare metodi tramite optional chaining <a href="#chiamare-metodi-tramite-optional-chaining" id="chiamare-metodi-tramite-optional-chaining"></a>

Puoi usare l'optional chaining per chiamare un metodo su un valore opzionale, e per verificare se quella chiamata al metodo ha successo. Puoi farlo anche se quel metodo non definisce un valore di ritorno.

Il metodo `printNumberOfRooms()` della classe `Residence` stampa il valore corrente di `numberOfRooms`. Ecco come appare il metodo:

```swift
func printNumberOfRooms() {
    print("The number of rooms is \(numberOfRooms)")
}
```

Questo metodo non specifica un tipo di ritorno. Tuttavia, le funzioni e i metodi privi di tipo di ritorno hanno un tipo di ritorno implicito `Void`, come descritto in [Funzioni senza valori di ritorno](/guida-al-linguaggio/funzioni.md#funzioni-senza-valori-di-ritorno). Ciò significa che restituiscono un valore `()`, ovvero una tupla vuota.

Se chiami questo metodo su un valore opzionale con l'optional chaining, il tipo di ritorno del metodo sarà `Void?`, non `Void`, perché i valori di ritorno sono sempre di tipo opzionale quando vengono chiamati tramite optional chaining. Questo ti permette di usare un'istruzione `if` per verificare se è stato possibile chiamare il metodo `printNumberOfRooms()`, anche se il metodo stesso non definisce un valore di ritorno. Confronta con `nil` il valore di ritorno della chiamata a `printNumberOfRooms` per vedere se la chiamata al metodo ha avuto successo:

```swift
if john.residence?.printNumberOfRooms() != nil {
    print("It was possible to print the number of rooms.")
} else {
    print("It was not possible to print the number of rooms.")
}
// Stampa "It was not possible to print the number of rooms."
```

Lo stesso vale se tenti di impostare una proprietà tramite optional chaining. L'esempio precedente in [Accedere alle proprietà tramite optional chaining](/guida-al-linguaggio/optional-chaining.md#accedere-alle-proprieta-tramite-optional-chaining) tenta di impostare un valore `address` per `john.residence`, anche se la proprietà `residence` è `nil`. Qualsiasi tentativo di impostare una proprietà tramite optional chaining restituisce un valore di tipo `Void?`, il che ti permette di confrontarlo con `nil` per vedere se la proprietà è stata impostata con successo:

```swift
if (john.residence?.address = someAddress) != nil {
    print("It was possible to set the address.")
} else {
    print("It was not possible to set the address.")
}
// Stampa "It was not possible to set the address."
```

## Accedere ai subscript tramite optional chaining <a href="#accedere-ai-subscript-tramite-optional-chaining" id="accedere-ai-subscript-tramite-optional-chaining"></a>

Puoi usare l'optional chaining per provare a recuperare e impostare un valore da un subscript su un valore opzionale, e per verificare se quella chiamata al subscript ha successo.

{% hint style="info" %}
**Nota:** Quando accedi a un subscript su un valore opzionale tramite optional chaining, collochi il punto interrogativo *prima* delle parentesi del subscript, non dopo. Il punto interrogativo dell'optional chaining segue sempre immediatamente la parte dell'espressione che è opzionale.
{% endhint %}

L'esempio seguente prova a recuperare il nome della prima stanza nell'array `rooms` della proprietà `john.residence` usando il subscript definito sulla classe `Residence`. Poiché `john.residence` è attualmente `nil`, la chiamata al subscript fallisce:

```swift
if let firstRoomName = john.residence?[0].name {
    print("The first room name is \(firstRoomName).")
} else {
    print("Unable to retrieve the first room name.")
}
// Stampa "Unable to retrieve the first room name."
```

Il punto interrogativo dell'optional chaining in questa chiamata al subscript è collocato immediatamente dopo `john.residence`, prima delle parentesi del subscript, perché `john.residence` è il valore opzionale su cui si sta tentando l'optional chaining.

Analogamente, puoi provare a impostare un nuovo valore tramite un subscript con l'optional chaining:

```swift
john.residence?[0] = Room(name: "Bathroom")
```

Anche questo tentativo di impostazione tramite subscript fallisce, perché `residence` è attualmente `nil`.

Se crei e assegni un'effettiva istanza di `Residence` a `john.residence`, con una o più istanze di `Room` nel suo array `rooms`, puoi usare il subscript di `Residence` per accedere agli elementi effettivi dell'array `rooms` tramite optional chaining:

```swift
let johnsHouse = Residence()
johnsHouse.rooms.append(Room(name: "Living Room"))
johnsHouse.rooms.append(Room(name: "Kitchen"))
john.residence = johnsHouse

if let firstRoomName = john.residence?[0].name {
    print("The first room name is \(firstRoomName).")
} else {
    print("Unable to retrieve the first room name.")
}
// Stampa "The first room name is Living Room."
```

### Accedere a subscript di tipo opzionale <a href="#accedere-a-subscript-di-tipo-opzionale" id="accedere-a-subscript-di-tipo-opzionale"></a>

Se un subscript restituisce un valore di tipo opzionale — come il subscript per chiave del tipo `Dictionary` di Swift — colloca un punto interrogativo *dopo* la parentesi di chiusura del subscript per concatenare sul suo valore di ritorno opzionale:

```swift
var testScores = ["Dave": [86, 82, 84], "Bev": [79, 94, 81]]
testScores["Dave"]?[0] = 91
testScores["Bev"]?[0] += 1
testScores["Brian"]?[0] = 72
// l'array "Dave" ora è [91, 82, 84] e l'array "Bev" ora è [80, 94, 81]
```

L'esempio qui sopra definisce un dizionario chiamato `testScores`, che contiene due coppie chiave-valore che associano una chiave `String` a un array di valori `Int`. L'esempio usa l'optional chaining per impostare a `91` il primo elemento dell'array `"Dave"`; per incrementare di `1` il primo elemento dell'array `"Bev"`; e per provare a impostare il primo elemento di un array per una chiave `"Brian"`. Le prime due chiamate hanno successo, perché il dizionario `testScores` contiene le chiavi `"Dave"` e `"Bev"`. La terza chiamata fallisce, perché il dizionario `testScores` non contiene una chiave `"Brian"`.

## Collegare più livelli di concatenamento <a href="#collegare-piu-livelli-di-concatenamento" id="collegare-piu-livelli-di-concatenamento"></a>

Puoi collegare tra loro più livelli di optional chaining per scendere a proprietà, metodi e subscript più in profondità all'interno di un modello. Tuttavia, più livelli di optional chaining non aggiungono ulteriori livelli di opzionalità al valore restituito.

Per dirla in altro modo:

* Se il tipo che stai cercando di recuperare non è opzionale, diventerà opzionale a causa dell'optional chaining.
* Se il tipo che stai cercando di recuperare è *già* opzionale, non diventerà *più* opzionale a causa del concatenamento.

Pertanto:

* Se provi a recuperare un valore `Int` tramite optional chaining, viene sempre restituito un `Int?`, indipendentemente da quanti livelli di concatenamento vengono usati.
* Analogamente, se provi a recuperare un valore `Int?` tramite optional chaining, viene sempre restituito un `Int?`, indipendentemente da quanti livelli di concatenamento vengono usati.

L'esempio seguente prova ad accedere alla proprietà `street` della proprietà `address` della proprietà `residence` di `john`. Qui sono in uso *due* livelli di optional chaining, per concatenare attraverso le proprietà `residence` e `address`, entrambe di tipo opzionale:

```swift
if let johnsStreet = john.residence?.address?.street {
    print("John's street name is \(johnsStreet).")
} else {
    print("Unable to retrieve the address.")
}
// Stampa "Unable to retrieve the address."
```

Il valore di `john.residence` contiene attualmente un'istanza valida di `Residence`. Tuttavia, il valore di `john.residence.address` è attualmente `nil`. Per questo motivo, la chiamata a `john.residence?.address?.street` fallisce.

Nota che nell'esempio qui sopra, stai cercando di recuperare il valore della proprietà `street`. Il tipo di questa proprietà è `String?`. Il valore di ritorno di `john.residence?.address?.street` è quindi anch'esso `String?`, anche se vengono applicati due livelli di optional chaining in aggiunta al tipo opzionale sottostante della proprietà.

Se imposti un'effettiva istanza di `Address` come valore di `john.residence.address`, e imposti un valore effettivo per la proprietà `street` dell'indirizzo, puoi accedere al valore della proprietà `street` tramite optional chaining su più livelli:

```swift
let johnsAddress = Address()
johnsAddress.buildingName = "The Larches"
johnsAddress.street = "Laurel Street"
john.residence?.address = johnsAddress

if let johnsStreet = john.residence?.address?.street {
    print("John's street name is \(johnsStreet).")
} else {
    print("Unable to retrieve the address.")
}
// Stampa "John's street name is Laurel Street."
```

In questo esempio, il tentativo di impostare la proprietà `address` di `john.residence` avrà successo, perché il valore di `john.residence` contiene attualmente un'istanza valida di `Residence`.

## Concatenare su metodi con valori di ritorno opzionali <a href="#concatenare-su-metodi-con-valori-di-ritorno-opzionali" id="concatenare-su-metodi-con-valori-di-ritorno-opzionali"></a>

L'esempio precedente mostra come recuperare il valore di una proprietà di tipo opzionale tramite optional chaining. Puoi anche usare l'optional chaining per chiamare un metodo che restituisce un valore di tipo opzionale, e per concatenare sul valore di ritorno di quel metodo, se necessario.

L'esempio seguente chiama il metodo `buildingIdentifier()` della classe `Address` tramite optional chaining. Questo metodo restituisce un valore di tipo `String?`. Come descritto sopra, il tipo di ritorno finale di questa chiamata al metodo dopo l'optional chaining è anch'esso `String?`:

```swift
if let buildingIdentifier = john.residence?.address?.buildingIdentifier() {
    print("John's building identifier is \(buildingIdentifier).")
}
// Stampa "John's building identifier is The Larches."
```

Se vuoi eseguire un ulteriore optional chaining sul valore di ritorno di questo metodo, colloca il punto interrogativo dell'optional chaining *dopo* le parentesi del metodo:

```swift
if let beginsWithThe =
    john.residence?.address?.buildingIdentifier()?.hasPrefix("The") {
    if beginsWithThe {
        print("John's building identifier begins with \"The\".")
    } else {
        print("John's building identifier doesn't begin with \"The\".")
    }
}
// Stampa "John's building identifier begins with "The"."
```

{% hint style="info" %}
**Nota:** Nell'esempio qui sopra, collochi il punto interrogativo dell'optional chaining *dopo* le parentesi, perché il valore opzionale su cui stai concatenando è il valore di ritorno del metodo `buildingIdentifier()`, e non il metodo `buildingIdentifier()` stesso.
{% endhint %}
