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

# Protocolli (Protocols)

Definisci i requisiti che i tipi conformi devono implementare.

Un *protocollo* definisce uno schema di metodi, proprietà e altri requisiti adatti a un particolare compito o a una particolare funzionalità. Il protocollo può poi essere *adottato* da una classe, una struttura o un'enumerazione per fornire un'implementazione effettiva di quei requisiti. Si dice che qualsiasi tipo che soddisfa i requisiti di un protocollo è *conforme* a quel protocollo.

Oltre a specificare i requisiti che i tipi conformi devono implementare, puoi estendere un protocollo per implementare alcuni di questi requisiti o per implementare funzionalità aggiuntive di cui i tipi conformi possono avvalersi.

## Sintassi dei protocolli <a href="#sintassi-dei-protocolli" id="sintassi-dei-protocolli"></a>

Definisci i protocolli in un modo molto simile a classi, strutture ed enumerazioni:

```swift
protocol SomeProtocol {
    // qui va la definizione del protocollo
}
```

I tipi personalizzati dichiarano di adottare un particolare protocollo collocando il nome del protocollo dopo il nome del tipo, separati da due punti, come parte della loro definizione. Si possono elencare più protocolli, separati da virgole:

```swift
struct SomeStructure: FirstProtocol, AnotherProtocol {
    // qui va la definizione della struttura
}
```

Se una classe ha una superclasse, elenca il nome della superclasse prima di tutti i protocolli che adotta, seguito da una virgola:

```swift
class SomeClass: SomeSuperclass, FirstProtocol, AnotherProtocol {
    // qui va la definizione della classe
}
```

{% hint style="info" %}
**Nota:** Poiché i protocolli sono tipi, fai iniziare i loro nomi con una lettera maiuscola (come `FullyNamed` e `RandomNumberGenerator`) per corrispondere ai nomi degli altri tipi in Swift (come `Int`, `String` e `Double`).
{% endhint %}

## Requisiti di proprietà <a href="#requisiti-di-proprieta" id="requisiti-di-proprieta"></a>

Un protocollo può richiedere a qualsiasi tipo conforme di fornire una proprietà di istanza o una proprietà di tipo con un nome e un tipo particolari. Il protocollo non specifica se la proprietà debba essere una proprietà memorizzata o una proprietà calcolata — specifica solo il nome e il tipo della proprietà richiesta. Il protocollo specifica anche se ciascuna proprietà debba essere leggibile (gettable) oppure leggibile *e* impostabile (settable).

Se un protocollo richiede che una proprietà sia leggibile e impostabile, quel requisito di proprietà non può essere soddisfatto da una proprietà memorizzata costante o da una proprietà calcolata di sola lettura. Se il protocollo richiede solo che una proprietà sia leggibile, il requisito può essere soddisfatto da qualsiasi tipo di proprietà, ed è valido che la proprietà sia anche impostabile se questo è utile per il tuo codice.

I requisiti di proprietà sono sempre dichiarati come proprietà variabili, precedute dalla parola chiave `var`. Le proprietà leggibili e impostabili si indicano scrivendo `{ get set }` dopo la dichiarazione del loro tipo, e le proprietà leggibili si indicano scrivendo `{ get }`.

```swift
protocol SomeProtocol {
    var mustBeSettable: Int { get set }
    var doesNotNeedToBeSettable: Int { get }
}
```

Fai sempre precedere i requisiti di proprietà di tipo dalla parola chiave `static` quando li definisci in un protocollo. Questa regola vale anche se i requisiti di proprietà di tipo possono essere preceduti dalla parola chiave `class` o `static` quando vengono implementati da una classe:

```swift
protocol AnotherProtocol {
    static var someTypeProperty: Int { get set }
}
```

Ecco un esempio di un protocollo con un unico requisito di proprietà di istanza:

```swift
protocol FullyNamed {
    var fullName: String { get }
}
```

Il protocollo `FullyNamed` richiede a un tipo conforme di fornire un nome completamente qualificato. Il protocollo non specifica nient'altro sulla natura del tipo conforme — specifica soltanto che il tipo deve essere in grado di fornire un nome completo per sé stesso. Il protocollo dichiara che qualsiasi tipo `FullyNamed` deve avere una proprietà di istanza leggibile chiamata `fullName`, di tipo `String`.

Ecco un esempio di una semplice struttura che adotta il protocollo `FullyNamed` ed è conforme a esso:

```swift
struct Person: FullyNamed {
    var fullName: String
}
let john = Person(fullName: "John Appleseed")
// john.fullName è "John Appleseed"
```

Questo esempio definisce una struttura chiamata `Person`, che rappresenta una specifica persona con un nome. Dichiara di adottare il protocollo `FullyNamed` come parte della prima riga della sua definizione.

Ogni istanza di `Person` ha un'unica proprietà memorizzata chiamata `fullName`, di tipo `String`. Questo corrisponde all'unico requisito del protocollo `FullyNamed`, e significa che `Person` è correttamente conforme al protocollo. (Swift segnala un errore in fase di compilazione se un requisito del protocollo non viene soddisfatto.)

Ecco una classe più complessa, anch'essa adottante e conforme al protocollo `FullyNamed`:

```swift
class Starship: FullyNamed {
    var prefix: String?
    var name: String
    init(name: String, prefix: String? = nil) {
        self.name = name
        self.prefix = prefix
    }
    var fullName: String {
        return (prefix != nil ? prefix! + " " : "") + name
    }
}
var ncc1701 = Starship(name: "Enterprise", prefix: "USS")
// ncc1701.fullName è "USS Enterprise"
```

Questa classe implementa il requisito di proprietà `fullName` come proprietà calcolata di sola lettura per un'astronave. Ogni istanza della classe `Starship` memorizza un `name` obbligatorio e un `prefix` opzionale. La proprietà `fullName` usa il valore di `prefix` se esiste, e lo antepone all'inizio di `name` per creare un nome completo per l'astronave.

## Requisiti di metodo <a href="#requisiti-di-metodo" id="requisiti-di-metodo"></a>

I protocolli possono richiedere che specifici metodi di istanza e metodi di tipo vengano implementati dai tipi conformi. Questi metodi si scrivono come parte della definizione del protocollo esattamente nello stesso modo dei normali metodi di istanza e di tipo, ma senza parentesi graffe né corpo del metodo. I parametri variadici sono consentiti, con le stesse regole dei normali metodi. Tuttavia, non si possono specificare valori predefiniti per i parametri dei metodi all'interno della definizione di un protocollo.

Come per i requisiti di proprietà di tipo, fai sempre precedere i requisiti di metodo di tipo dalla parola chiave `static` quando sono definiti in un protocollo. Questo vale anche se i requisiti di metodo di tipo sono preceduti dalla parola chiave `class` o `static` quando vengono implementati da una classe:

```swift
protocol SomeProtocol {
    static func someTypeMethod()
}
```

L'esempio seguente definisce un protocollo con un unico requisito di metodo di istanza:

```swift
protocol RandomNumberGenerator {
    func random() -> Double
}
```

Questo protocollo, `RandomNumberGenerator`, richiede a qualsiasi tipo conforme di avere un metodo di istanza chiamato `random`, che restituisce un valore `Double` ogni volta che viene chiamato. Sebbene non sia specificato come parte del protocollo, si presume che questo valore sarà un numero compreso tra `0.0` e `1.0` (escluso).

Il protocollo `RandomNumberGenerator` non fa alcuna supposizione su come verrà generato ciascun numero casuale — richiede semplicemente che il generatore fornisca un modo standard per generare un nuovo numero casuale.

Ecco l'implementazione di una classe che adotta il protocollo `RandomNumberGenerator` ed è conforme a esso. Questa classe implementa un algoritmo di generazione di numeri pseudocasuali noto come *generatore lineare congruenziale*:

```swift
class LinearCongruentialGenerator: RandomNumberGenerator {
    var lastRandom = 42.0
    let m = 139968.0
    let a = 3877.0
    let c = 29573.0
    func random() -> Double {
        lastRandom = ((lastRandom * a + c)
            .truncatingRemainder(dividingBy:m))
        return lastRandom / m
    }
}
let generator = LinearCongruentialGenerator()
print("Here's a random number: \(generator.random())")
// Stampa "Here's a random number: 0.3746499199817101".
print("And another one: \(generator.random())")
// Stampa "And another one: 0.729023776863283".
```

## Requisiti di metodo mutating <a href="#requisiti-di-metodo-mutating" id="requisiti-di-metodo-mutating"></a>

A volte è necessario che un metodo modifichi (o *muti*) l'istanza a cui appartiene. Per i metodi di istanza dei tipi valore (cioè strutture ed enumerazioni) collochi la parola chiave `mutating` prima della parola chiave `func` di un metodo per indicare che il metodo può modificare l'istanza a cui appartiene e qualsiasi proprietà di quell'istanza. Questo processo è descritto in [Modificare i tipi valore dall'interno dei metodi di istanza](/guida-al-linguaggio/metodi.md#modificare-i-tipi-valore-dallinterno-dei-metodi-di-istanza).

Se definisci un requisito di metodo di istanza di un protocollo destinato a mutare le istanze di qualsiasi tipo che adotta il protocollo, contrassegna il metodo con la parola chiave `mutating` come parte della definizione del protocollo. Questo permette a strutture ed enumerazioni di adottare il protocollo e di soddisfare quel requisito di metodo.

{% hint style="info" %}
**Nota:** Se contrassegni un requisito di metodo di istanza di un protocollo come `mutating`, non hai bisogno di scrivere la parola chiave `mutating` quando scrivi un'implementazione di quel metodo per una classe. La parola chiave `mutating` viene usata solo da strutture ed enumerazioni.
{% endhint %}

L'esempio seguente definisce un protocollo chiamato `Togglable`, che definisce un unico requisito di metodo di istanza chiamato `toggle`. Come suggerisce il nome, il metodo `toggle()` ha lo scopo di commutare o invertire lo stato di qualsiasi tipo conforme, tipicamente modificando una proprietà di quel tipo.

Il metodo `toggle()` è contrassegnato con la parola chiave `mutating` come parte della definizione del protocollo `Togglable`, per indicare che ci si aspetta che il metodo muti lo stato di un'istanza conforme quando viene chiamato:

```swift
protocol Togglable {
    mutating func toggle()
}
```

Se implementi il protocollo `Togglable` per una struttura o un'enumerazione, quella struttura o enumerazione può essere conforme al protocollo fornendo un'implementazione del metodo `toggle()` anch'essa contrassegnata come `mutating`.

L'esempio seguente definisce un'enumerazione chiamata `OnOffSwitch`. Questa enumerazione commuta tra due stati, indicati dai casi dell'enumerazione `on` e `off`. L'implementazione di `toggle` dell'enumerazione è contrassegnata come `mutating`, per corrispondere ai requisiti del protocollo `Togglable`:

```swift
enum OnOffSwitch: Togglable {
    case off, on
    mutating func toggle() {
        switch self {
        case .off:
            self = .on
        case .on:
            self = .off
        }
    }
}
var lightSwitch = OnOffSwitch.off
lightSwitch.toggle()
// lightSwitch ora è uguale a .on
```

## Requisiti di inizializzatore <a href="#requisiti-di-inizializzatore" id="requisiti-di-inizializzatore"></a>

I protocolli possono richiedere che specifici inizializzatori vengano implementati dai tipi conformi. Scrivi questi inizializzatori come parte della definizione del protocollo esattamente nello stesso modo dei normali inizializzatori, ma senza parentesi graffe né corpo dell'inizializzatore:

```swift
protocol SomeProtocol {
    init(someParameter: Int)
}
```

### Implementazioni in una classe dei requisiti di inizializzatore di un protocollo <a href="#implementazioni-in-una-classe-dei-requisiti-di-inizializzatore-di-un-protocollo" id="implementazioni-in-una-classe-dei-requisiti-di-inizializzatore-di-un-protocollo"></a>

Puoi implementare un requisito di inizializzatore di un protocollo su una classe conforme come inizializzatore designato oppure come inizializzatore di convenienza. In entrambi i casi, devi contrassegnare l'implementazione dell'inizializzatore con il modificatore `required`:

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

L'uso del modificatore `required` garantisce che fornisci un'implementazione esplicita o ereditata del requisito di inizializzatore su tutte le sottoclassi della classe conforme, in modo che anch'esse siano conformi al protocollo.

Per maggiori informazioni sugli inizializzatori required, vedi [Inizializzatori required](/guida-al-linguaggio/inizializzazione.md#inizializzatori-required).

{% hint style="info" %}
**Nota:** Non hai bisogno di contrassegnare le implementazioni degli inizializzatori dei protocolli con il modificatore `required` sulle classi contrassegnate con il modificatore `final`, perché le classi final non possono avere sottoclassi. Per saperne di più sul modificatore `final`, vedi [Impedire gli override](/guida-al-linguaggio/ereditarieta.md#impedire-gli-override).
{% endhint %}

Se una sottoclasse sovrascrive un inizializzatore designato di una superclasse, e implementa anche un requisito di inizializzatore corrispondente di un protocollo, contrassegna l'implementazione dell'inizializzatore con entrambi i modificatori `required` e `override`:

```swift
protocol SomeProtocol {
    init()
}

class SomeSuperClass {
    init() {
        // qui va l'implementazione dell'inizializzatore
    }
}

class SomeSubClass: SomeSuperClass, SomeProtocol {
    // "required" per la conformità a SomeProtocol; "override" per SomeSuperClass
    required override init() {
        // qui va l'implementazione dell'inizializzatore
    }
}
```

### Requisiti di inizializzatore failable <a href="#requisiti-di-inizializzatore-failable" id="requisiti-di-inizializzatore-failable"></a>

I protocolli possono definire requisiti di inizializzatore failable per i tipi conformi, come definito in [Inizializzatori failable](/guida-al-linguaggio/inizializzazione.md#inizializzatori-failable).

Un requisito di inizializzatore failable può essere soddisfatto da un inizializzatore failable o non failable su un tipo conforme. Un requisito di inizializzatore non failable può essere soddisfatto da un inizializzatore non failable o da un inizializzatore failable con unwrapping implicito.

## Protocolli che hanno solo requisiti semantici <a href="#protocolli-che-hanno-solo-requisiti-semantici" id="protocolli-che-hanno-solo-requisiti-semantici"></a>

Tutti i protocolli di esempio visti sopra richiedono alcuni metodi o proprietà, ma la dichiarazione di un protocollo non deve necessariamente includere requisiti. Puoi anche usare un protocollo per descrivere requisiti *semantici* — cioè requisiti su come si comportano i valori di quei tipi e sulle operazioni che supportano. La libreria standard di Swift definisce diversi protocolli che non hanno alcun metodo o proprietà richiesti:

* [`Sendable`](https://developer.apple.com/documentation/swift/sendable) per i valori che possono essere condivisi tra domini di concorrenza, come discusso in [Tipi Sendable](/guida-al-linguaggio/concorrenza.md#tipi-sendable).
* [`Copyable`](https://developer.apple.com/documentation/swift/copyable) per i valori che Swift può copiare quando li passi a una funzione, come discusso in [Parametri borrowing e consuming](/riferimento-del-linguaggio/dichiarazioni.md#parametri-borrowing-e-consuming).
* [`BitwiseCopyable`](https://developer.apple.com/documentation/swift/bitwisecopyable) per i valori che possono essere copiati bit per bit.

Per informazioni sui requisiti di questi protocolli, vedi la panoramica nella loro documentazione.

Per adottare questi protocolli usi la stessa sintassi che usi per adottare gli altri protocolli. L'unica differenza è che non includi dichiarazioni di metodi o proprietà che implementano i requisiti del protocollo. Per esempio:

```swift
struct MyStruct: Copyable {
    var counter = 12
}

extension MyStruct: BitwiseCopyable { }
```

Il codice qui sopra definisce una nuova struttura. Poiché `Copyable` ha solo requisiti semantici, nella dichiarazione della struttura non c'è alcun codice per adottare il protocollo. Analogamente, poiché `BitwiseCopyable` ha solo requisiti semantici, l'estensione che adotta quel protocollo ha un corpo vuoto.

Di solito non hai bisogno di scrivere la conformità a questi protocolli — è invece Swift ad aggiungere implicitamente la conformità per te, come descritto in [Conformità implicita a un protocollo](/guida-al-linguaggio/protocolli.md#conformita-implicita-a-un-protocollo).

## I protocolli come tipi <a href="#i-protocolli-come-tipi" id="i-protocolli-come-tipi"></a>

I protocolli in realtà non implementano di per sé alcuna funzionalità. Ciononostante, puoi usare un protocollo come tipo nel tuo codice.

Il modo più comune di usare un protocollo come tipo è usarlo come vincolo generico. Il codice con vincoli generici può lavorare con qualsiasi tipo conforme al protocollo, e il tipo specifico viene scelto dal codice che usa l'API. Per esempio, quando chiami una funzione che accetta un argomento e il tipo di quell'argomento è generico, è il chiamante a scegliere il tipo.

Il codice con un tipo opaco lavora con un qualche tipo conforme al protocollo. Il tipo sottostante è noto in fase di compilazione, ed è l'implementazione dell'API a scegliere quel tipo, ma l'identità di quel tipo è nascosta ai client dell'API. Usare un tipo opaco ti permette di impedire che i dettagli di implementazione di un'API trapelino attraverso lo strato di astrazione — per esempio, nascondendo il tipo di ritorno specifico di una funzione, e garantendo soltanto che il valore sia conforme a un dato protocollo.

Il codice con un tipo protocollo boxed lavora con qualsiasi tipo, scelto in fase di esecuzione, conforme al protocollo. Per supportare questa flessibilità in fase di esecuzione, Swift aggiunge un livello di indirezione quando necessario — noto come *box* (scatola), che ha un costo in termini di prestazioni. A causa di questa flessibilità, Swift non conosce il tipo sottostante in fase di compilazione, il che significa che puoi accedere solo ai membri richiesti dal protocollo. Accedere a qualsiasi altra API del tipo sottostante richiede una conversione in fase di esecuzione.

Per informazioni sull'uso dei protocolli come vincoli generici, vedi [Generici](/guida-al-linguaggio/generici.md). Per informazioni sui tipi opachi e sui tipi protocollo boxed, vedi [Tipi opachi e tipi protocollo boxed](/guida-al-linguaggio/tipi-opachi-e-tipi-protocollo-boxed.md).

## Delega <a href="#delega" id="delega"></a>

La *delega* (delegation) è uno schema di progettazione che permette a una classe o a una struttura di affidare (o *delegare*) alcune delle sue responsabilità a un'istanza di un altro tipo. Questo schema di progettazione si implementa definendo un protocollo che incapsula le responsabilità delegate, in modo tale che un tipo conforme (noto come delegate) garantisca di fornire la funzionalità che è stata delegata. La delega può essere usata per rispondere a una particolare azione, o per recuperare dati da una fonte esterna senza bisogno di conoscere il tipo sottostante di quella fonte.

L'esempio seguente definisce un gioco di dadi e un protocollo annidato per un delegate che tiene traccia dei progressi del gioco:

```swift
class DiceGame {
    let sides: Int
    let generator = LinearCongruentialGenerator()
    weak var delegate: Delegate?

    init(sides: Int) {
        self.sides = sides
    }

    func roll() -> Int {
        return Int(generator.random() * Double(sides)) + 1
    }

    func play(rounds: Int) {
        delegate?.gameDidStart(self)
        for round in 1...rounds {
            let player1 = roll()
            let player2 = roll()
            if player1 == player2 {
                delegate?.game(self, didEndRound: round, winner: nil)
            } else if player1 > player2 {
                delegate?.game(self, didEndRound: round, winner: 1)
            } else {
                delegate?.game(self, didEndRound: round, winner: 2)
            }
        }
        delegate?.gameDidEnd(self)
    }

    protocol Delegate: AnyObject {
        func gameDidStart(_ game: DiceGame)
        func game(_ game: DiceGame, didEndRound round: Int, winner: Int?)
        func gameDidEnd(_ game: DiceGame)
    }
}
```

La classe `DiceGame` implementa un gioco in cui ogni giocatore a turno lancia i dadi, e il giocatore che ottiene il numero più alto vince il round. Usa un generatore lineare congruenziale dell'esempio precedente del capitolo, per generare numeri casuali per i lanci dei dadi.

Il protocollo `DiceGame.Delegate` può essere adottato per tenere traccia dei progressi di una partita a dadi. Poiché il protocollo `DiceGame.Delegate` viene sempre usato nel contesto di una partita a dadi, è annidato all'interno della classe `DiceGame`. I protocolli possono essere annidati all'interno di dichiarazioni di tipo come strutture e classi, purché la dichiarazione esterna non sia generica. Per informazioni sull'annidamento dei tipi, vedi [Tipi annidati](/guida-al-linguaggio/tipi-annidati.md).

Per prevenire i cicli di riferimenti forti, i delegate sono dichiarati come riferimenti weak. Per informazioni sui riferimenti weak, vedi [Cicli di riferimenti forti tra istanze di classe](/guida-al-linguaggio/conteggio-automatico-dei-riferimenti.md#cicli-di-riferimenti-forti-tra-istanze-di-classe). Contrassegnare il protocollo come riservato alle classi (class-only) permette alla classe `DiceGame` di dichiarare che il suo delegate deve usare un riferimento weak. Un protocollo riservato alle classi è contrassegnato dalla sua ereditarietà da `AnyObject`, come discusso in [Protocolli riservati alle classi](/guida-al-linguaggio/protocolli.md#protocolli-riservati-alle-classi).

`DiceGame.Delegate` fornisce tre metodi per tenere traccia dei progressi di una partita. Questi tre metodi sono incorporati nella logica del gioco nel metodo `play(rounds:)` visto sopra. La classe `DiceGame` chiama i metodi del suo delegate quando inizia una nuova partita, inizia un nuovo turno o la partita termina.

Poiché la proprietà `delegate` è un `DiceGame.Delegate` *opzionale*, il metodo `play(rounds:)` usa l'optional chaining ogni volta che chiama un metodo sul delegate, come discusso in [Optional chaining](/guida-al-linguaggio/optional-chaining.md). Se la proprietà `delegate` è nil, queste chiamate al delegate vengono ignorate. Se la proprietà `delegate` non è nil, i metodi del delegate vengono chiamati, e ricevono l'istanza di `DiceGame` come parametro.

Il prossimo esempio mostra una classe chiamata `DiceGameTracker`, che adotta il protocollo `DiceGame.Delegate`:

```swift
class DiceGameTracker: DiceGame.Delegate {
    var playerScore1 = 0
    var playerScore2 = 0
    func gameDidStart(_ game: DiceGame) {
        print("Started a new game")
        playerScore1 = 0
        playerScore2 = 0
    }
    func game(_ game: DiceGame, didEndRound round: Int, winner: Int?) {
        switch winner {
            case 1:
                playerScore1 += 1
                print("Player 1 won round \(round)")
            case 2: playerScore2 += 1
                print("Player 2 won round \(round)")
            default:
                print("The round was a draw")
        }
    }
    func gameDidEnd(_ game: DiceGame) {
        if playerScore1 == playerScore2 {
            print("The game ended in a draw.")
        } else if playerScore1 > playerScore2 {
            print("Player 1 won!")
        } else {
            print("Player 2 won!")
        }
    }
}
```

La classe `DiceGameTracker` implementa tutti e tre i metodi richiesti dal protocollo `DiceGame.Delegate`. Usa questi metodi per azzerare i punteggi di entrambi i giocatori all'inizio di una nuova partita, per aggiornare i loro punteggi alla fine di ogni round, e per annunciare un vincitore alla fine della partita.

Ecco come appaiono `DiceGame` e `DiceGameTracker` in azione:

```swift
let tracker = DiceGameTracker()
let game = DiceGame(sides: 6)
game.delegate = tracker
game.play(rounds: 3)
// Started a new game
// Player 2 won round 1
// Player 2 won round 2
// Player 1 won round 3
// Player 2 won!
```

## Aggiungere la conformità a un protocollo con un'estensione <a href="#aggiungere-la-conformita-a-un-protocollo-con-unestensione" id="aggiungere-la-conformita-a-un-protocollo-con-unestensione"></a>

Puoi estendere un tipo esistente affinché adotti un nuovo protocollo e sia conforme a esso, anche se non hai accesso al codice sorgente del tipo esistente. Le estensioni possono aggiungere nuove proprietà, metodi e subscript a un tipo esistente, e sono quindi in grado di aggiungere qualsiasi requisito che un protocollo possa richiedere. Per saperne di più sulle estensioni, vedi [Estensioni](/guida-al-linguaggio/estensioni.md).

{% hint style="info" %}
**Nota:** Le istanze esistenti di un tipo adottano automaticamente un protocollo e sono conformi a esso quando quella conformità viene aggiunta al tipo dell'istanza in un'estensione.
{% endhint %}

Per esempio, questo protocollo, chiamato `TextRepresentable`, può essere implementato da qualsiasi tipo che abbia un modo per essere rappresentato come testo. Potrebbe trattarsi di una descrizione di sé stesso, o di una versione testuale del suo stato corrente:

```swift
protocol TextRepresentable {
    var textualDescription: String { get }
}
```

La classe `Dice` vista sopra può essere estesa affinché adotti `TextRepresentable` e sia conforme a esso:

```swift
extension Dice: TextRepresentable {
    var textualDescription: String {
        return "A \(sides)-sided dice"
    }
}
```

Questa estensione adotta il nuovo protocollo esattamente nello stesso modo in cui lo avrebbe fatto `Dice` se lo avesse fornito nella sua implementazione originale. Il nome del protocollo viene fornito dopo il nome del tipo, separato da due punti, e un'implementazione di tutti i requisiti del protocollo viene fornita all'interno delle parentesi graffe dell'estensione.

Qualsiasi istanza di `Dice` può ora essere trattata come `TextRepresentable`:

```swift
let d12 = Dice(sides: 12, generator: LinearCongruentialGenerator())
print(d12.textualDescription)
// Stampa "A 12-sided dice".
```

Analogamente, la classe di gioco `SnakesAndLadders` può essere estesa affinché adotti il protocollo `TextRepresentable` e sia conforme a esso:

```swift
extension SnakesAndLadders: TextRepresentable {
    var textualDescription: String {
        return "A game of Snakes and Ladders with \(finalSquare) squares"
    }
}
print(game.textualDescription)
// Stampa "A game of Snakes and Ladders with 25 squares".
```

### Conformità condizionale a un protocollo <a href="#conformita-condizionale-a-un-protocollo" id="conformita-condizionale-a-un-protocollo"></a>

Un tipo generico potrebbe essere in grado di soddisfare i requisiti di un protocollo solo in determinate condizioni, per esempio quando il parametro generico del tipo è conforme al protocollo. Puoi rendere un tipo generico conforme a un protocollo in modo condizionale elencando dei vincoli quando estendi il tipo. Scrivi questi vincoli dopo il nome del protocollo che stai adottando scrivendo una clausola `where` generica. Per saperne di più sulle clausole `where` generiche, vedi [Clausole where generiche](/guida-al-linguaggio/generici.md#clausole-where-generiche).

L'estensione seguente rende le istanze di `Array` conformi al protocollo `TextRepresentable` ogni volta che memorizzano elementi di un tipo conforme a `TextRepresentable`.

```swift
extension Array: TextRepresentable where Element: TextRepresentable {
    var textualDescription: String {
        let itemsAsText = self.map { $0.textualDescription }
        return "[" + itemsAsText.joined(separator: ", ") + "]"
    }
}
let myDice = [d6, d12]
print(myDice.textualDescription)
// Stampa "[A 6-sided dice, A 12-sided dice]".
```

### Dichiarare l'adozione di un protocollo con un'estensione <a href="#dichiarare-ladozione-di-un-protocollo-con-unestensione" id="dichiarare-ladozione-di-un-protocollo-con-unestensione"></a>

Se un tipo è già conforme a tutti i requisiti di un protocollo, ma non ha ancora dichiarato di adottare quel protocollo, puoi fargli adottare il protocollo con un'estensione vuota:

```swift
struct Hamster {
    var name: String
    var textualDescription: String {
        return "A hamster named \(name)"
    }
}
extension Hamster: TextRepresentable {}
```

Le istanze di `Hamster` possono ora essere usate ovunque `TextRepresentable` sia il tipo richiesto:

```swift
let simonTheHamster = Hamster(name: "Simon")
let somethingTextRepresentable: TextRepresentable = simonTheHamster
print(somethingTextRepresentable.textualDescription)
// Stampa "A hamster named Simon".
```

{% hint style="info" %}
**Nota:** I tipi non adottano automaticamente un protocollo solo perché ne soddisfano i requisiti. Devono sempre dichiarare esplicitamente la loro adozione del protocollo.
{% endhint %}

## Adottare un protocollo usando un'implementazione sintetizzata <a href="#adottare-un-protocollo-usando-unimplementazione-sintetizzata" id="adottare-un-protocollo-usando-unimplementazione-sintetizzata"></a>

Swift può fornire automaticamente la conformità al protocollo per `Equatable`, `Hashable` e `Comparable` in molti casi semplici. Usare questa implementazione sintetizzata significa che non devi scrivere codice boilerplate ripetitivo per implementare tu stesso i requisiti del protocollo.

Swift fornisce un'implementazione sintetizzata di `Equatable` per i seguenti tipi personalizzati:

* Strutture che hanno solo proprietà memorizzate conformi al protocollo `Equatable`
* Enumerazioni che hanno solo tipi associati conformi al protocollo `Equatable`
* Enumerazioni che non hanno tipi associati

Per ricevere un'implementazione sintetizzata di `==`, dichiara la conformità a `Equatable` nel file che contiene la dichiarazione originale, senza implementare tu stesso un operatore `==`. Il protocollo `Equatable` fornisce un'implementazione predefinita di `!=`.

L'esempio seguente definisce una struttura `Vector3D` per un vettore di posizione tridimensionale `(x, y, z)`, simile alla struttura `Vector2D`. Poiché le proprietà `x`, `y` e `z` sono tutte di un tipo `Equatable`, `Vector3D` riceve implementazioni sintetizzate degli operatori di equivalenza.

```swift
struct Vector3D: Equatable {
    var x = 0.0, y = 0.0, z = 0.0
}

let twoThreeFour = Vector3D(x: 2.0, y: 3.0, z: 4.0)
let anotherTwoThreeFour = Vector3D(x: 2.0, y: 3.0, z: 4.0)
if twoThreeFour == anotherTwoThreeFour {
    print("These two vectors are also equivalent.")
}
// Stampa "These two vectors are also equivalent."
```

Swift fornisce un'implementazione sintetizzata di `Hashable` per i seguenti tipi personalizzati:

* Strutture che hanno solo proprietà memorizzate conformi al protocollo `Hashable`
* Enumerazioni che hanno solo tipi associati conformi al protocollo `Hashable`
* Enumerazioni che non hanno tipi associati

Per ricevere un'implementazione sintetizzata di `hash(into:)`, dichiara la conformità a `Hashable` nel file che contiene la dichiarazione originale, senza implementare tu stesso un metodo `hash(into:)`.

Swift fornisce un'implementazione sintetizzata di `Comparable` per le enumerazioni che non hanno un valore grezzo. Se l'enumerazione ha tipi associati, questi devono essere tutti conformi al protocollo `Comparable`. Per ricevere un'implementazione sintetizzata di `<`, dichiara la conformità a `Comparable` nel file che contiene la dichiarazione originale dell'enumerazione, senza implementare tu stesso un operatore `<`. L'implementazione predefinita di `<=`, `>` e `>=` del protocollo `Comparable` fornisce gli operatori di confronto rimanenti.

L'esempio seguente definisce un'enumerazione `SkillLevel` con casi per principianti, livello intermedio ed esperti. Gli esperti sono inoltre classificati in base al numero di stelle che hanno.

```swift
enum SkillLevel: Comparable {
    case beginner
    case intermediate
    case expert(stars: Int)
}
var levels = [SkillLevel.intermediate, SkillLevel.beginner,
              SkillLevel.expert(stars: 5), SkillLevel.expert(stars: 3)]
for level in levels.sorted() {
    print(level)
}
// Stampa "beginner".
// Stampa "intermediate".
// Stampa "expert(stars: 3)".
// Stampa "expert(stars: 5)".
```

## Conformità implicita a un protocollo <a href="#conformita-implicita-a-un-protocollo" id="conformita-implicita-a-un-protocollo"></a>

Alcuni protocolli sono così comuni che li scriveresti quasi ogni volta che dichiari un nuovo tipo. Per i protocolli seguenti, Swift inferisce automaticamente la conformità quando definisci un tipo che implementa i requisiti del protocollo, quindi non devi scriverli tu:

* [`Copyable`](https://developer.apple.com/documentation/swift/copyable)
* [`Sendable`](https://developer.apple.com/documentation/swift/sendable)
* [`BitwiseCopyable`](https://developer.apple.com/documentation/swift/bitwisecopyable)

Puoi comunque scrivere esplicitamente la conformità, ma questo non cambia il comportamento del tuo codice. Per sopprimere una conformità implicita, scrivi una tilde (`~`) prima del nome del protocollo nell'elenco delle conformità:

```swift
struct FileDescriptor: ~Sendable {
    let rawValue: Int
}
```

Il codice qui sopra mostra una parte di un wrapper attorno ai descrittori di file POSIX. La struttura `FileDescriptor` soddisfa tutti i requisiti del protocollo `Sendable`, il che normalmente la renderebbe sendable. Tuttavia, scrivere `~Sendable` sopprime questa conformità implicita. Anche se i descrittori di file usano interi per identificare i file aperti e interagire con essi, e i valori interi sono sendable, renderla non sendable può aiutare a evitare certi tipi di bug.

Un altro modo per sopprimere la conformità implicita è con un'estensione che contrassegni come non disponibile:

```swift
@available(*, unavailable)
extension FileDescriptor: Sendable { }
```

Quando scrivi `~Sendable` in un punto del tuo codice, come nell'esempio precedente, il codice altrove nel tuo programma può comunque estendere il tipo `FileDescriptor` per aggiungere la conformità a `Sendable`. Al contrario, l'estensione non disponibile di questo esempio sopprime la conformità implicita a `Sendable` e impedisce inoltre a qualsiasi estensione altrove nel tuo codice di aggiungere al tipo la conformità a `Sendable`.

{% hint style="info" %}
**Nota:** Oltre ai protocolli discussi sopra, gli actor distribuiti sono implicitamente conformi al protocollo [`Codable`](https://developer.apple.com/documentation/swift/codable).
{% endhint %}

## Collezioni di tipi protocollo <a href="#collezioni-di-tipi-protocollo" id="collezioni-di-tipi-protocollo"></a>

Un protocollo può essere usato come tipo da memorizzare in una collezione come un array o un dizionario, come accennato in [I protocolli come tipi](/guida-al-linguaggio/protocolli.md#i-protocolli-come-tipi). Questo esempio crea un array di elementi `TextRepresentable`:

```swift
let things: [TextRepresentable] = [game, d12, simonTheHamster]
```

Ora è possibile iterare sugli elementi dell'array, e stampare la descrizione testuale di ciascun elemento:

```swift
for thing in things {
    print(thing.textualDescription)
}
// A game of Snakes and Ladders with 25 squares
// A 12-sided dice
// A hamster named Simon
```

Nota che la costante `thing` è di tipo `TextRepresentable`. Non è di tipo `Dice`, né `DiceGame`, né `Hamster`, anche se l'istanza effettiva dietro le quinte è di uno di quei tipi. Ciononostante, poiché è di tipo `TextRepresentable`, e di qualsiasi cosa sia `TextRepresentable` si sa che ha una proprietà `textualDescription`, è sicuro accedere a `thing.textualDescription` a ogni passaggio del ciclo.

## Ereditarietà dei protocolli <a href="#ereditarieta-dei-protocolli" id="ereditarieta-dei-protocolli"></a>

Un protocollo può *ereditare* uno o più altri protocolli e può aggiungere ulteriori requisiti a quelli che eredita. La sintassi dell'ereditarietà dei protocolli è simile a quella dell'ereditarietà delle classi, ma con la possibilità di elencare più protocolli ereditati, separati da virgole:

```swift
protocol InheritingProtocol: SomeProtocol, AnotherProtocol {
    // qui va la definizione del protocollo
}
```

Ecco un esempio di un protocollo che eredita il protocollo `TextRepresentable` visto sopra:

```swift
protocol PrettyTextRepresentable: TextRepresentable {
    var prettyTextualDescription: String { get }
}
```

Questo esempio definisce un nuovo protocollo, `PrettyTextRepresentable`, che eredita da `TextRepresentable`. Qualsiasi cosa adotti `PrettyTextRepresentable` deve soddisfare tutti i requisiti imposti da `TextRepresentable`, *più* i requisiti aggiuntivi imposti da `PrettyTextRepresentable`. In questo esempio, `PrettyTextRepresentable` aggiunge un unico requisito: fornire una proprietà leggibile chiamata `prettyTextualDescription` che restituisce una `String`.

La classe `SnakesAndLadders` può essere estesa affinché adotti `PrettyTextRepresentable` e sia conforme a esso:

```swift
extension SnakesAndLadders: PrettyTextRepresentable {
    var prettyTextualDescription: String {
        var output = textualDescription + ":\n"
        for index in 1...finalSquare {
            switch board[index] {
            case let ladder where ladder > 0:
                output += "▲ "
            case let snake where snake < 0:
                output += "▼ "
            default:
                output += "○ "
            }
        }
        return output
    }
}
```

Questa estensione dichiara di adottare il protocollo `PrettyTextRepresentable` e fornisce un'implementazione della proprietà `prettyTextualDescription` per il tipo `SnakesAndLadders`. Qualsiasi cosa sia `PrettyTextRepresentable` deve essere anche `TextRepresentable`, e quindi l'implementazione di `prettyTextualDescription` inizia accedendo alla proprietà `textualDescription` del protocollo `TextRepresentable` per iniziare una stringa di output. Vi aggiunge due punti e un'interruzione di riga, e usa questo come inizio della sua rappresentazione testuale formattata. Poi itera sull'array delle caselle del tabellone, e aggiunge una forma geometrica per rappresentare il contenuto di ciascuna casella:

* Se il valore della casella è maggiore di `0`, si tratta della base di una scala, ed è rappresentata da `▲`.
* Se il valore della casella è minore di `0`, si tratta della testa di un serpente, ed è rappresentata da `▼`.
* Altrimenti, il valore della casella è `0`, e si tratta di una casella “libera”, rappresentata da `○`.

La proprietà `prettyTextualDescription` può ora essere usata per stampare una descrizione testuale formattata di qualsiasi istanza di `SnakesAndLadders`:

```swift
print(game.prettyTextualDescription)
// A game of Snakes and Ladders with 25 squares:
// ○ ○ ▲ ○ ○ ▲ ○ ○ ▲ ▲ ○ ○ ○ ▼ ○ ○ ○ ○ ▼ ○ ○ ▼ ○ ▼ ○
```

## Protocolli riservati alle classi <a href="#protocolli-riservati-alle-classi" id="protocolli-riservati-alle-classi"></a>

Puoi limitare l'adozione di un protocollo ai tipi classe (e non a strutture o enumerazioni) aggiungendo il protocollo `AnyObject` all'elenco di ereditarietà di un protocollo.

```swift
protocol SomeClassOnlyProtocol: AnyObject, SomeInheritedProtocol {
    // qui va la definizione del protocollo riservato alle classi
}
```

Nell'esempio qui sopra, `SomeClassOnlyProtocol` può essere adottato solo da tipi classe. È un errore in fase di compilazione scrivere la definizione di una struttura o di un'enumerazione che tenti di adottare `SomeClassOnlyProtocol`.

{% hint style="info" %}
**Nota:** Usa un protocollo riservato alle classi quando il comportamento definito dai requisiti di quel protocollo presuppone o richiede che un tipo conforme abbia una semantica di riferimento anziché una semantica di valore. Per saperne di più sulla semantica di riferimento e di valore, vedi [Strutture ed enumerazioni sono tipi valore](/guida-al-linguaggio/strutture-e-classi.md#strutture-ed-enumerazioni-sono-tipi-valore) e [Le classi sono tipi riferimento](/guida-al-linguaggio/strutture-e-classi.md#le-classi-sono-tipi-riferimento).
{% endhint %}

Puoi anche indicare una classe specifica nell'elenco di ereditarietà di un protocollo per richiedere che tutti i tipi conformi siano sottoclassi di quella classe.

```swift
class Renderer {
    func render(_ text: String) {
        print(text)
    }
}

protocol Widget: Renderer {
    var title: String { get }
}

extension Widget {
    func display() {
        render(title)
    }
}

class ButtonWidget: Renderer, Widget {
    var title: String
    init(title: String) {
        self.title = title
    }
}

let button = ButtonWidget(title: "OK")
button.display()
// Stampa "OK".
```

Nell'esempio qui sopra, `Widget` può essere adottato solo da sottoclassi di `Renderer`. Poiché il protocollo garantisce che ogni tipo conforme sia una sottoclasse di `Renderer`, l'estensione del protocollo `Widget` può chiamare direttamente `render(_:)`. Un requisito di superclasse è più restrittivo dell'uso di `AnyObject`: limita la conformità a una specifica gerarchia di classi, non a qualsiasi tipo classe. Usalo quando l'implementazione del protocollo dipende dal comportamento concreto di una particolare classe base.

## Composizione di protocolli <a href="#composizione-di-protocolli" id="composizione-di-protocolli"></a>

Può essere utile richiedere che un tipo sia conforme a più protocolli contemporaneamente. Puoi combinare più protocolli in un unico requisito con una *composizione di protocolli*. Le composizioni di protocolli si comportano come se tu avessi definito un protocollo locale temporaneo con i requisiti combinati di tutti i protocolli della composizione. Le composizioni di protocolli non definiscono nuovi tipi protocollo.

Le composizioni di protocolli hanno la forma `SomeProtocol & AnotherProtocol`. Puoi elencare tutti i protocolli di cui hai bisogno, separandoli con delle e commerciali (`&`). Oltre al suo elenco di protocolli, una composizione di protocolli può contenere anche un tipo classe, che puoi usare per specificare una superclasse richiesta.

Ecco un esempio che combina due protocolli chiamati `Named` e `Aged` in un unico requisito di composizione di protocolli sul parametro di una funzione:

```swift
protocol Named {
    var name: String { get }
}
protocol Aged {
    var age: Int { get }
}
struct Person: Named, Aged {
    var name: String
    var age: Int
}
func wishHappyBirthday(to celebrator: Named & Aged) {
    print("Happy birthday, \(celebrator.name), you're \(celebrator.age)!")
}
let birthdayPerson = Person(name: "Malcolm", age: 21)
wishHappyBirthday(to: birthdayPerson)
// Stampa "Happy birthday, Malcolm, you're 21!"
```

In questo esempio, il protocollo `Named` ha un unico requisito: una proprietà `String` leggibile chiamata `name`. Il protocollo `Aged` ha un unico requisito: una proprietà `Int` leggibile chiamata `age`. Entrambi i protocolli sono adottati da una struttura chiamata `Person`.

L'esempio definisce anche una funzione `wishHappyBirthday(to:)`. Il tipo del parametro `celebrator` è `Named & Aged`, che significa “qualsiasi tipo conforme sia al protocollo `Named` sia al protocollo `Aged`”. Non importa quale tipo specifico venga passato alla funzione, purché sia conforme a entrambi i protocolli richiesti.

L'esempio crea poi una nuova istanza di `Person` chiamata `birthdayPerson` e passa questa nuova istanza alla funzione `wishHappyBirthday(to:)`. Poiché `Person` è conforme a entrambi i protocolli, questa chiamata è valida, e la funzione `wishHappyBirthday(to:)` può stampare il suo augurio di compleanno.

Ecco un esempio che combina il protocollo `Named` dell'esempio precedente con una classe `Location`:

```swift
class Location {
    var latitude: Double
    var longitude: Double
    init(latitude: Double, longitude: Double) {
        self.latitude = latitude
        self.longitude = longitude
    }
}
class City: Location, Named {
    var name: String
    init(name: String, latitude: Double, longitude: Double) {
        self.name = name
        super.init(latitude: latitude, longitude: longitude)
    }
}
func beginConcert(in location: Location & Named) {
    print("Hello, \(location.name)!")
}

let seattle = City(name: "Seattle", latitude: 47.6, longitude: -122.3)
beginConcert(in: seattle)
// Stampa "Hello, Seattle!"
```

La funzione `beginConcert(in:)` accetta un parametro di tipo `Location & Named`, che significa "qualsiasi tipo che sia una sottoclasse di `Location` e che sia conforme al protocollo `Named`". In questo caso, `City` soddisfa entrambi i requisiti.

Passare `birthdayPerson` alla funzione `beginConcert(in:)` non è valido perché `Person` non è una sottoclasse di `Location`. Allo stesso modo, se creassi una sottoclasse di `Location` che non fosse conforme al protocollo `Named`, anche chiamare `beginConcert(in:)` con un'istanza di quel tipo non sarebbe valido.

## Verificare la conformità a un protocollo <a href="#verificare-la-conformita-a-un-protocollo" id="verificare-la-conformita-a-un-protocollo"></a>

Puoi usare gli operatori `is` e `as` descritti in [Type casting](/guida-al-linguaggio/type-casting.md) per verificare la conformità a un protocollo, e per convertire a un protocollo specifico. La verifica e la conversione verso un protocollo seguono esattamente la stessa sintassi della verifica e della conversione verso un tipo:

* L'operatore `is` restituisce `true` se un'istanza è conforme a un protocollo e restituisce `false` se non lo è.
* La versione `as?` dell'operatore di downcast restituisce un valore opzionale del tipo del protocollo, e questo valore è `nil` se l'istanza non è conforme a quel protocollo.
* La versione `as!` dell'operatore di downcast forza il downcast al tipo del protocollo e attiva un errore in fase di esecuzione se il downcast non ha successo.

Questo esempio definisce un protocollo chiamato `HasArea`, con un unico requisito di proprietà: una proprietà `Double` leggibile chiamata `area`:

```swift
protocol HasArea {
    var area: Double { get }
}
```

Ecco due classi, `Circle` e `Country`, entrambe conformi al protocollo `HasArea`:

```swift
class Circle: HasArea {
    let pi = 3.1415927
    var radius: Double
    var area: Double { return pi * radius * radius }
    init(radius: Double) { self.radius = radius }
}
class Country: HasArea {
    var area: Double
    init(area: Double) { self.area = area }
}
```

La classe `Circle` implementa il requisito di proprietà `area` come proprietà calcolata, basata su una proprietà memorizzata `radius`. La classe `Country` implementa il requisito `area` direttamente come proprietà memorizzata. Entrambe le classi sono correttamente conformi al protocollo `HasArea`.

Ecco una classe chiamata `Animal`, che non è conforme al protocollo `HasArea`:

```swift
class Animal {
    var legs: Int
    init(legs: Int) { self.legs = legs }
}
```

Le classi `Circle`, `Country` e `Animal` non hanno una classe base comune. Ciononostante, sono tutte classi, e quindi le istanze di tutti e tre i tipi possono essere usate per inizializzare un array che memorizza valori di tipo `AnyObject`:

```swift
let objects: [AnyObject] = [
    Circle(radius: 2.0),
    Country(area: 243_610),
    Animal(legs: 4)
]
```

L'array `objects` viene inizializzato con un letterale array contenente un'istanza di `Circle` con un raggio di 2 unità; un'istanza di `Country` inizializzata con la superficie del Regno Unito in chilometri quadrati; e un'istanza di `Animal` con quattro zampe.

Ora si può iterare sull'array `objects`, e ogni oggetto dell'array può essere verificato per vedere se è conforme al protocollo `HasArea`:

```swift
for object in objects {
    if let objectWithArea = object as? HasArea {
        print("Area is \(objectWithArea.area)")
    } else {
        print("Something that doesn't have an area")
    }
}
// Area is 12.5663708
// Area is 243610.0
// Something that doesn't have an area
```

Ogni volta che un oggetto dell'array è conforme al protocollo `HasArea`, il valore opzionale restituito dall'operatore `as?` viene estratto con l'optional binding in una costante chiamata `objectWithArea`. È noto che la costante `objectWithArea` è di tipo `HasArea`, e quindi si può accedere alla sua proprietà `area` e stamparla in modo sicuro rispetto ai tipi.

Nota che gli oggetti sottostanti non vengono modificati dal processo di conversione. Continuano a essere un `Circle`, un `Country` e un `Animal`. Tuttavia, nel momento in cui vengono memorizzati nella costante `objectWithArea`, si sa soltanto che sono di tipo `HasArea`, e quindi si può accedere solo alla loro proprietà `area`.

## Requisiti opzionali dei protocolli <a href="#requisiti-opzionali-dei-protocolli" id="requisiti-opzionali-dei-protocolli"></a>

Puoi definire *requisiti opzionali* per i protocolli. Questi requisiti non devono necessariamente essere implementati dai tipi conformi al protocollo. I requisiti opzionali sono preceduti dal modificatore `optional` come parte della definizione del protocollo. I requisiti opzionali sono disponibili affinché tu possa scrivere codice che interagisca con Objective-C. Sia il protocollo sia il requisito opzionale devono essere contrassegnati con l'attributo `@objc`. Nota che i protocolli `@objc` possono essere adottati solo da classi, non da strutture o enumerazioni.

Quando usi un metodo o una proprietà in un requisito opzionale, il suo tipo diventa automaticamente opzionale. Per esempio, un metodo di tipo `(Int) -> String` diventa `((Int) -> String)?`. Nota che è l'intero tipo funzione a essere racchiuso nell'opzionale, non il valore di ritorno del metodo.

Un requisito opzionale di un protocollo può essere chiamato con l'optional chaining, per tenere conto della possibilità che il requisito non sia stato implementato da un tipo conforme al protocollo. Verifichi la presenza di un'implementazione di un metodo opzionale scrivendo un punto interrogativo dopo il nome del metodo quando lo chiami, come in `someOptionalMethod?(someArgument)`. Per informazioni sull'optional chaining, vedi [Optional chaining](/guida-al-linguaggio/optional-chaining.md).

L'esempio seguente definisce una classe di conteggio di interi chiamata `Counter`, che usa una fonte di dati esterna per fornire la quantità del suo incremento. Questa fonte di dati è definita dal protocollo `CounterDataSource`, che ha due requisiti opzionali:

```swift
@objc protocol CounterDataSource {
    @objc optional func increment(forCount count: Int) -> Int
    @objc optional var fixedIncrement: Int { get }
}
```

Il protocollo `CounterDataSource` definisce un requisito di metodo opzionale chiamato `increment(forCount:)` e un requisito di proprietà opzionale chiamato `fixedIncrement`. Questi requisiti definiscono due modi diversi con cui le fonti di dati possono fornire una quantità di incremento appropriata per un'istanza di `Counter`.

{% hint style="info" %}
**Nota:** A rigor di termini, puoi scrivere una classe personalizzata conforme a `CounterDataSource` senza implementare *nessuno* dei due requisiti del protocollo. Dopotutto, sono entrambi opzionali. Sebbene tecnicamente consentito, questo non costituirebbe una fonte di dati molto utile.
{% endhint %}

La classe `Counter`, definita di seguito, ha una proprietà opzionale `dataSource` di tipo `CounterDataSource?`:

```swift
class Counter {
    var count = 0
    var dataSource: CounterDataSource?
    func increment() {
        if let amount = dataSource?.increment?(forCount: count) {
            count += amount
        } else if let amount = dataSource?.fixedIncrement {
            count += amount
        }
    }
}
```

La classe `Counter` memorizza il suo valore corrente in una proprietà variabile chiamata `count`. La classe `Counter` definisce anche un metodo chiamato `increment`, che incrementa la proprietà `count` ogni volta che il metodo viene chiamato.

Il metodo `increment()` prova innanzitutto a recuperare una quantità di incremento cercando un'implementazione del metodo `increment(forCount:)` nella sua fonte di dati. Il metodo `increment()` usa l'optional chaining per provare a chiamare `increment(forCount:)`, e passa il valore corrente di `count` come unico argomento del metodo.

Nota che qui sono in gioco *due* livelli di optional chaining. Innanzitutto, è possibile che `dataSource` sia `nil`, e quindi `dataSource` ha un punto interrogativo dopo il suo nome per indicare che `increment(forCount:)` deve essere chiamato solo se `dataSource` non è `nil`. In secondo luogo, anche se `dataSource` *esiste*, non c'è alcuna garanzia che implementi `increment(forCount:)`, perché è un requisito opzionale. Qui, la possibilità che `increment(forCount:)` non sia implementato è anch'essa gestita dall'optional chaining. La chiamata a `increment(forCount:)` avviene solo se `increment(forCount:)` esiste — cioè, se non è `nil`. Ecco perché anche `increment(forCount:)` è scritto con un punto interrogativo dopo il suo nome.

Poiché la chiamata a `increment(forCount:)` può fallire per uno di questi due motivi, la chiamata restituisce un valore `Int` *opzionale*. Questo è vero anche se `increment(forCount:)` è definito come restituente un valore `Int` non opzionale nella definizione di `CounterDataSource`. Anche se ci sono due operazioni di optional chaining, una dopo l'altra, il risultato è comunque racchiuso in un unico opzionale. Per maggiori informazioni sull'uso di più operazioni di optional chaining, vedi [Collegare più livelli di concatenamento](/guida-al-linguaggio/optional-chaining.md#collegare-piu-livelli-di-concatenamento).

Dopo aver chiamato `increment(forCount:)`, viene fatto l'unwrapping dell'`Int` opzionale che restituisce in una costante chiamata `amount`, usando l'optional binding. Se l'`Int` opzionale contiene effettivamente un valore — cioè, se il delegate e il metodo esistono entrambi, e il metodo ha restituito un valore — l'`amount` estratto viene aggiunto alla proprietà memorizzata `count`, e l'incremento è completato.

Se *non* è possibile recuperare un valore dal metodo `increment(forCount:)` — perché `dataSource` è nil, oppure perché la fonte di dati non implementa `increment(forCount:)` — allora il metodo `increment()` prova invece a recuperare un valore dalla proprietà `fixedIncrement` della fonte di dati. Anche la proprietà `fixedIncrement` è un requisito opzionale, quindi il suo valore è un valore `Int` opzionale, anche se `fixedIncrement` è definita come proprietà `Int` non opzionale come parte della definizione del protocollo `CounterDataSource`.

Ecco una semplice implementazione di `CounterDataSource` in cui la fonte di dati restituisce un valore costante di `3` ogni volta che viene interrogata. Lo fa implementando il requisito di proprietà opzionale `fixedIncrement`:

```swift
class ThreeSource: NSObject, CounterDataSource {
    let fixedIncrement = 3
}
```

Puoi usare un'istanza di `ThreeSource` come fonte di dati per una nuova istanza di `Counter`:

```swift
var counter = Counter()
counter.dataSource = ThreeSource()
for _ in 1...4 {
    counter.increment()
    print(counter.count)
}
// 3
// 6
// 9
// 12
```

Il codice qui sopra crea una nuova istanza di `Counter`; imposta la sua fonte di dati a una nuova istanza di `ThreeSource`; e chiama il metodo `increment()` del contatore quattro volte. Come previsto, la proprietà `count` del contatore aumenta di tre ogni volta che viene chiamato `increment()`.

Ecco una fonte di dati più complessa chiamata `TowardsZeroSource`, che fa contare un'istanza di `Counter` in avanti o all'indietro verso zero a partire dal suo valore corrente di `count`:

```swift
class TowardsZeroSource: NSObject, CounterDataSource {
    func increment(forCount count: Int) -> Int {
        if count == 0 {
            return 0
        } else if count < 0 {
            return 1
        } else {
            return -1
        }
    }
}
```

La classe `TowardsZeroSource` implementa il metodo opzionale `increment(forCount:)` del protocollo `CounterDataSource` e usa il valore dell'argomento `count` per stabilire in quale direzione contare. Se `count` è già zero, il metodo restituisce `0` per indicare che non deve avvenire alcun ulteriore conteggio.

Puoi usare un'istanza di `TowardsZeroSource` con l'istanza esistente di `Counter` per contare da `-4` a zero. Una volta che il contatore raggiunge lo zero, non avviene più alcun conteggio:

```swift
counter.count = -4
counter.dataSource = TowardsZeroSource()
for _ in 1...5 {
    counter.increment()
    print(counter.count)
}
// -3
// -2
// -1
// 0
// 0
```

## Estensioni dei protocolli <a href="#estensioni-dei-protocolli" id="estensioni-dei-protocolli"></a>

I protocolli possono essere estesi per fornire implementazioni di metodi, inizializzatori, subscript e proprietà calcolate ai tipi conformi. Questo ti permette di definire un comportamento sui protocolli stessi, anziché nella conformità individuale di ciascun tipo o in una funzione globale.

Per esempio, il protocollo `RandomNumberGenerator` può essere esteso per fornire un metodo `randomBool()`, che usa il risultato del metodo richiesto `random()` per restituire un valore `Bool` casuale:

```swift
extension RandomNumberGenerator {
    func randomBool() -> Bool {
        return random() > 0.5
    }
}
```

Creando un'estensione del protocollo, tutti i tipi conformi ottengono automaticamente l'implementazione di questo metodo senza alcuna modifica aggiuntiva.

```swift
let generator = LinearCongruentialGenerator()
print("Here's a random number: \(generator.random())")
// Stampa "Here's a random number: 0.3746499199817101".
print("And here's a random Boolean: \(generator.randomBool())")
// Stampa "And here's a random Boolean: true".
```

Le estensioni dei protocolli possono aggiungere implementazioni ai tipi conformi ma non possono far sì che un protocollo estenda un altro protocollo o erediti da esso. L'ereditarietà dei protocolli è sempre specificata nella dichiarazione del protocollo stesso.

### Fornire implementazioni predefinite <a href="#fornire-implementazioni-predefinite" id="fornire-implementazioni-predefinite"></a>

Puoi usare le estensioni dei protocolli per fornire un'implementazione predefinita per qualsiasi requisito di metodo o di proprietà calcolata di quel protocollo. Se un tipo conforme fornisce una propria implementazione di un metodo o di una proprietà richiesti, verrà usata quell'implementazione invece di quella fornita dall'estensione.

{% hint style="info" %}
**Nota:** I requisiti dei protocolli con implementazioni predefinite fornite dalle estensioni sono distinti dai requisiti opzionali dei protocolli. Sebbene i tipi conformi non debbano fornire una propria implementazione né degli uni né degli altri, i requisiti con implementazioni predefinite possono essere chiamati senza optional chaining.
{% endhint %}

Per esempio, il protocollo `PrettyTextRepresentable`, che eredita il protocollo `TextRepresentable`, può fornire un'implementazione predefinita della sua proprietà richiesta `prettyTextualDescription` che restituisce semplicemente il risultato dell'accesso alla proprietà `textualDescription`:

```swift
extension PrettyTextRepresentable  {
    var prettyTextualDescription: String {
        return textualDescription
    }
}
```

### Aggiungere vincoli alle estensioni dei protocolli <a href="#aggiungere-vincoli-alle-estensioni-dei-protocolli" id="aggiungere-vincoli-alle-estensioni-dei-protocolli"></a>

Quando definisci un'estensione di un protocollo, puoi specificare dei vincoli che i tipi conformi devono soddisfare prima che i metodi e le proprietà dell'estensione siano disponibili. Scrivi questi vincoli dopo il nome del protocollo che stai estendendo scrivendo una clausola `where` generica. Per saperne di più sulle clausole `where` generiche, vedi [Clausole where generiche](/guida-al-linguaggio/generici.md#clausole-where-generiche).

Per esempio, puoi definire un'estensione del protocollo `Collection` che si applica a qualsiasi collezione i cui elementi siano conformi al protocollo `Equatable`. Vincolando gli elementi di una collezione al protocollo `Equatable`, che fa parte della libreria standard di Swift, puoi usare gli operatori `==` e `!=` per verificare l'uguaglianza e la disuguaglianza tra due elementi.

```swift
extension Collection where Element: Equatable {
    func allEqual() -> Bool {
        for element in self {
            if element != self.first {
                return false
            }
        }
        return true
    }
}
```

Il metodo `allEqual()` restituisce `true` solo se tutti gli elementi della collezione sono uguali.

Considera due array di interi, uno in cui tutti gli elementi sono uguali, e uno in cui non lo sono:

```swift
let equalNumbers = [100, 100, 100, 100, 100]
let differentNumbers = [100, 100, 200, 100, 200]
```

Poiché gli array sono conformi a `Collection` e gli interi sono conformi a `Equatable`, `equalNumbers` e `differentNumbers` possono usare il metodo `allEqual()`:

```swift
print(equalNumbers.allEqual())
// Stampa "true".
print(differentNumbers.allEqual())
// Stampa "false".
```

{% hint style="info" %}
**Nota:** Se un tipo conforme soddisfa i requisiti di più estensioni vincolate che forniscono implementazioni per lo stesso metodo o la stessa proprietà, Swift usa l'implementazione corrispondente ai vincoli più specializzati.
{% endhint %}
