> 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/gestione-degli-errori.md).

# Gestione degli errori (Error Handling)

Rispondi agli errori e riprenditi da essi.

La *gestione degli errori* è il processo con cui si risponde alle condizioni di errore nel proprio programma e ci si riprende da esse. Swift fornisce un supporto di prima classe per lanciare, catturare, propagare e manipolare errori recuperabili in fase di esecuzione.

Alcune operazioni non hanno la garanzia di completare sempre l'esecuzione o di produrre un output utile. Gli opzionali vengono usati per rappresentare l'assenza di un valore, ma quando un'operazione fallisce, è spesso utile capire che cosa ha causato il fallimento, in modo che il tuo codice possa rispondere di conseguenza.

Come esempio, considera il compito di leggere ed elaborare dati da un file su disco. Ci sono diversi modi in cui questo compito può fallire, tra cui il fatto che il file non esista al percorso specificato, che il file non abbia i permessi di lettura, o che il file non sia codificato in un formato compatibile. Distinguere tra queste diverse situazioni permette a un programma di risolvere alcuni errori e di comunicare all'utente gli errori che non può risolvere.

{% hint style="info" %}
**Nota:** La gestione degli errori in Swift interagisce con gli schemi di gestione degli errori che usano la classe `NSError` in Cocoa e Objective-C. Per maggiori informazioni su questa classe, vedi [Handling Cocoa Errors in Swift](https://developer.apple.com/documentation/swift/cocoa_design_patterns/handling_cocoa_errors_in_swift).
{% endhint %}

## Rappresentare e lanciare errori <a href="#rappresentare-e-lanciare-errori" id="rappresentare-e-lanciare-errori"></a>

In Swift, gli errori sono rappresentati da valori di tipi conformi al protocollo `Error`. Questo protocollo vuoto indica che un tipo può essere usato per la gestione degli errori.

Le enumerazioni di Swift sono particolarmente adatte a modellare un gruppo di condizioni di errore correlate, con valori associati che permettono di comunicare informazioni aggiuntive sulla natura di un errore. Per esempio, ecco come potresti rappresentare le condizioni di errore del funzionamento di un distributore automatico all'interno di un gioco:

```swift
enum VendingMachineError: Error {
    case invalidSelection
    case insufficientFunds(coinsNeeded: Int)
    case outOfStock
}
```

Lanciare un errore ti permette di indicare che è successo qualcosa di inatteso e che il normale flusso di esecuzione non può continuare. Usi un'istruzione `throw` per lanciare un errore. Per esempio, il codice seguente lancia un errore per indicare che il distributore automatico ha bisogno di altre cinque monete:

```swift
throw VendingMachineError.insufficientFunds(coinsNeeded: 5)
```

## Gestire gli errori <a href="#gestire-gli-errori" id="gestire-gli-errori"></a>

Quando viene lanciato un errore, una qualche porzione di codice circostante deve essere responsabile della gestione dell'errore — per esempio, correggendo il problema, tentando un approccio alternativo, o informando l'utente del fallimento.

In Swift ci sono quattro modi per gestire gli errori. Puoi propagare l'errore da una funzione al codice che chiama quella funzione, gestire l'errore usando un'istruzione `do`-`catch`, gestire l'errore come valore opzionale, oppure asserire che l'errore non si verificherà. Ciascun approccio è descritto in una sezione seguente.

Quando una funzione lancia un errore, cambia il flusso del tuo programma, quindi è importante che tu possa identificare rapidamente i punti del tuo codice che possono lanciare errori. Per identificare questi punti nel tuo codice, scrivi la parola chiave `try` — o la sua variante `try?` o `try!` — prima di una porzione di codice che chiama una funzione, un metodo o un inizializzatore che può lanciare un errore. Queste parole chiave sono descritte nelle sezioni seguenti.

{% hint style="info" %}
**Nota:** La gestione degli errori in Swift somiglia alla gestione delle eccezioni in altri linguaggi, con l'uso delle parole chiave `try`, `catch` e `throw`. A differenza della gestione delle eccezioni in molti linguaggi — compreso Objective-C — la gestione degli errori in Swift non comporta lo srotolamento dello stack delle chiamate, un processo che può essere computazionalmente costoso. Di conseguenza, le caratteristiche prestazionali di un'istruzione `throw` sono paragonabili a quelle di un'istruzione `return`.
{% endhint %}

### Propagare gli errori usando funzioni che lanciano errori <a href="#propagare-gli-errori-usando-funzioni-che-lanciano-errori" id="propagare-gli-errori-usando-funzioni-che-lanciano-errori"></a>

Per indicare che una funzione, un metodo o un inizializzatore può lanciare un errore, scrivi la parola chiave `throws` nella dichiarazione della funzione dopo i suoi parametri. Una funzione contrassegnata con `throws` è chiamata *funzione che lancia errori* (throwing function). Se la funzione specifica un tipo di ritorno, scrivi la parola chiave `throws` prima della freccia di ritorno (`->`).

```swift
func canThrowErrors() throws -> String

func cannotThrowErrors() -> String
```

Una funzione che lancia errori propaga gli errori lanciati al suo interno all'ambito da cui viene chiamata.

{% hint style="info" %}
**Nota:** Solo le funzioni che lanciano errori possono propagare errori. Qualsiasi errore lanciato all'interno di una funzione che non lancia errori deve essere gestito all'interno della funzione.
{% endhint %}

Nell'esempio seguente, la classe `VendingMachine` ha un metodo `vend(itemNamed:)` che lancia un `VendingMachineError` appropriato se l'articolo richiesto non è disponibile, è esaurito, o ha un costo che supera l'importo depositato corrente:

```swift
struct Item {
    var price: Int
    var count: Int
}

class VendingMachine {
    var inventory = [
        "Candy Bar": Item(price: 12, count: 7),
        "Chips": Item(price: 10, count: 4),
        "Pretzels": Item(price: 7, count: 11)
    ]
    var coinsDeposited = 0

    func vend(itemNamed name: String) throws {
        guard let item = inventory[name] else {
            throw VendingMachineError.invalidSelection
        }

        guard item.count > 0 else {
            throw VendingMachineError.outOfStock
        }

        guard item.price <= coinsDeposited else {
            throw VendingMachineError.insufficientFunds(coinsNeeded: item.price - coinsDeposited)
        }

        coinsDeposited -= item.price

        var newItem = item
        newItem.count -= 1
        inventory[name] = newItem

        print("Dispensing \(name)")
    }
}
```

L'implementazione del metodo `vend(itemNamed:)` usa istruzioni `guard` per uscire anticipatamente dal metodo e lanciare gli errori appropriati se uno qualsiasi dei requisiti per l'acquisto di uno snack non è soddisfatto. Poiché un'istruzione `throw` trasferisce immediatamente il controllo del programma, un articolo verrà erogato solo se tutti questi requisiti sono soddisfatti.

Poiché il metodo `vend(itemNamed:)` propaga tutti gli errori che lancia, qualsiasi codice che chiama questo metodo deve gestire gli errori — usando un'istruzione `do`-`catch`, `try?` o `try!` — oppure continuare a propagarli. Per esempio, `buyFavoriteSnack(person:vendingMachine:)` nell'esempio seguente è anch'essa una funzione che lancia errori, e tutti gli errori lanciati dal metodo `vend(itemNamed:)` si propagheranno fino al punto in cui viene chiamata la funzione `buyFavoriteSnack(person:vendingMachine:)`.

```swift
let favoriteSnacks = [
    "Alice": "Chips",
    "Bob": "Licorice",
    "Eve": "Pretzels",
]
func buyFavoriteSnack(person: String, vendingMachine: VendingMachine) throws {
    let snackName = favoriteSnacks[person] ?? "Candy Bar"
    try vendingMachine.vend(itemNamed: snackName)
}
```

In questo esempio, la funzione `buyFavoriteSnack(person: vendingMachine:)` cerca lo snack preferito di una data persona e prova a comprarlo per lei chiamando il metodo `vend(itemNamed:)`. Poiché il metodo `vend(itemNamed:)` può lanciare un errore, viene chiamato con la parola chiave `try` davanti.

Gli inizializzatori che lanciano errori possono propagare gli errori nello stesso modo delle funzioni che lanciano errori. Per esempio, l'inizializzatore della struttura `PurchasedSnack` nel listato seguente chiama una funzione che lancia errori come parte del processo di inizializzazione, e gestisce tutti gli errori che incontra propagandoli al suo chiamante.

```swift
struct PurchasedSnack {
    let name: String
    init(name: String, vendingMachine: VendingMachine) throws {
        try vendingMachine.vend(itemNamed: name)
        self.name = name
    }
}
```

### Gestire gli errori usando do-catch <a href="#gestire-gli-errori-usando-do-catch" id="gestire-gli-errori-usando-do-catch"></a>

Usi un'istruzione `do`-`catch` per gestire gli errori eseguendo un blocco di codice. Se il codice nella clausola `do` lancia un errore, questo viene confrontato con le clausole `catch` per determinare quale di esse può gestire l'errore.

Ecco la forma generale di un'istruzione `do`-`catch`:

```swift
do {
    try <#expression#>
    <#statements#>
} catch <#pattern 1#> {
    <#statements#>
} catch <#pattern 2#> where <#condition#> {
    <#statements#>
} catch <#pattern 3#>, <#pattern 4#> where <#condition#> {
    <#statements#>
} catch {
    <#statements#>
}
```

Scrivi un pattern dopo `catch` per indicare quali errori quella clausola può gestire. Se una clausola `catch` non ha un pattern, la clausola corrisponde a qualsiasi errore e associa l'errore a una costante locale chiamata `error`. Per maggiori informazioni sul pattern matching, vedi [Pattern](/riferimento-del-linguaggio/pattern.md).

Per esempio, il codice seguente confronta l'errore con tutti e tre i casi dell'enumerazione `VendingMachineError`.

```swift
var vendingMachine = VendingMachine()
vendingMachine.coinsDeposited = 8
do {
    try buyFavoriteSnack(person: "Alice", vendingMachine: vendingMachine)
    print("Success! Yum.")
} catch VendingMachineError.invalidSelection {
    print("Invalid Selection.")
} catch VendingMachineError.outOfStock {
    print("Out of Stock.")
} catch VendingMachineError.insufficientFunds(let coinsNeeded) {
    print("Insufficient funds. Please insert an additional \(coinsNeeded) coins.")
} catch {
    print("Unexpected error: \(error).")
}
// Stampa "Insufficient funds. Please insert an additional 2 coins."
```

Nell'esempio qui sopra, la funzione `buyFavoriteSnack(person:vendingMachine:)` viene chiamata in un'espressione `try`, perché può lanciare un errore. Se viene lanciato un errore, l'esecuzione passa immediatamente alle clausole `catch`, che decidono se consentire che la propagazione continui. Se nessun pattern corrisponde, l'errore viene catturato dalla clausola `catch` finale e viene associato a una costante locale `error`. Se non viene lanciato alcun errore, vengono eseguite le istruzioni rimanenti dell'istruzione `do`.

Le clausole `catch` non devono gestire ogni possibile errore che il codice nella clausola `do` può lanciare. Se nessuna delle clausole `catch` gestisce l'errore, l'errore si propaga all'ambito circostante. Tuttavia, l'errore propagato deve essere gestito da *un qualche* ambito circostante. In una funzione che non lancia errori, deve essere un'istruzione `do`-`catch` che la racchiude a gestire l'errore. In una funzione che lancia errori, deve essere un'istruzione `do`-`catch` che la racchiude oppure il chiamante a gestire l'errore. Se l'errore si propaga fino all'ambito di livello superiore senza essere gestito, otterrai un errore in fase di esecuzione.

Per esempio, l'esempio qui sopra può essere scritto in modo che qualsiasi errore che non sia un `VendingMachineError` venga invece catturato dalla funzione chiamante:

```swift
func nourish(with item: String) throws {
    do {
        try vendingMachine.vend(itemNamed: item)
    } catch is VendingMachineError {
        print("Couldn't buy that from the vending machine.")
    }
}

do {
    try nourish(with: "Beet-Flavored Chips")
} catch {
    print("Unexpected non-vending-machine-related error: \(error)")
}
// Stampa "Couldn't buy that from the vending machine."
```

Nella funzione `nourish(with:)`, se `vend(itemNamed:)` lancia un errore che è uno dei casi dell'enumerazione `VendingMachineError`, `nourish(with:)` gestisce l'errore stampando un messaggio. Altrimenti, `nourish(with:)` propaga l'errore al punto in cui è stata chiamata. L'errore viene quindi catturato dalla clausola `catch` generica.

Un altro modo per catturare diversi errori correlati è elencarli dopo `catch`, separati da virgole. Per esempio:

```swift
func eat(item: String) throws {
    do {
        try vendingMachine.vend(itemNamed: item)
    } catch VendingMachineError.invalidSelection, VendingMachineError.insufficientFunds, VendingMachineError.outOfStock {
        print("Invalid selection, out of stock, or not enough money.")
    }
}
```

La funzione `eat(item:)` elenca gli errori del distributore automatico da catturare, e il suo testo di errore corrisponde agli elementi di quell'elenco. Se viene lanciato uno qualsiasi dei tre errori elencati, questa clausola `catch` li gestisce stampando un messaggio. Tutti gli altri errori vengono propagati all'ambito circostante, compresi eventuali errori del distributore automatico che potrebbero essere aggiunti in seguito.

### Convertire gli errori in valori opzionali <a href="#convertire-gli-errori-in-valori-opzionali" id="convertire-gli-errori-in-valori-opzionali"></a>

Usi `try?` per gestire un errore convertendolo in un valore opzionale. Se viene lanciato un errore durante la valutazione dell'espressione `try?`, il valore dell'espressione è `nil`. Per esempio, nel codice seguente `x` e `y` hanno lo stesso valore e lo stesso comportamento:

```swift
func someThrowingFunction() throws -> Int {
    // ...
}

let x = try? someThrowingFunction()

let y: Int?
do {
    y = try someThrowingFunction()
} catch {
    y = nil
}
```

Se `someThrowingFunction()` lancia un errore, il valore di `x` e `y` è `nil`. Altrimenti, il valore di `x` e `y` è il valore restituito dalla funzione. Nota che `x` e `y` sono un opzionale del tipo restituito da `someThrowingFunction()`, qualunque esso sia. Qui la funzione restituisce un intero, quindi `x` e `y` sono interi opzionali.

Usare `try?` ti permette di scrivere codice di gestione degli errori conciso quando vuoi gestire tutti gli errori nello stesso modo. Per esempio, il codice seguente usa diversi approcci per recuperare i dati, oppure restituisce `nil` se tutti gli approcci falliscono.

```swift
func fetchData() -> Data? {
    if let data = try? fetchDataFromDisk() { return data }
    if let data = try? fetchDataFromServer() { return data }
    return nil
}
```

### Disabilitare la propagazione degli errori <a href="#disabilitare-la-propagazione-degli-errori" id="disabilitare-la-propagazione-degli-errori"></a>

A volte sai che una funzione o un metodo che lancia errori di fatto non lancerà un errore in fase di esecuzione. In queste occasioni, puoi scrivere `try!` prima dell'espressione per disabilitare la propagazione degli errori e racchiudere la chiamata in un'asserzione in fase di esecuzione secondo cui non verrà lanciato alcun errore. Se viene effettivamente lanciato un errore, otterrai un errore in fase di esecuzione.

Per esempio, il codice seguente usa una funzione `loadImage(atPath:)`, che carica la risorsa immagine a un dato percorso o lancia un errore se l'immagine non può essere caricata. In questo caso, poiché l'immagine è distribuita insieme all'applicazione, non verrà lanciato alcun errore in fase di esecuzione, quindi è appropriato disabilitare la propagazione degli errori.

```swift
let photo = try! loadImage(atPath: "./Resources/John Appleseed.jpg")
```

## Specificare il tipo di errore <a href="#specificare-il-tipo-di-errore" id="specificare-il-tipo-di-errore"></a>

Tutti gli esempi precedenti usano il tipo più comune di gestione degli errori, in cui gli errori che il tuo codice lancia possono essere valori di qualsiasi tipo conforme al protocollo `Error`. Questo approccio corrisponde alla realtà per cui non conosci in anticipo ogni errore che potrebbe verificarsi mentre il codice è in esecuzione, soprattutto quando propaghi errori lanciati altrove. Riflette inoltre il fatto che gli errori possono cambiare nel tempo. Nuove versioni di una libreria — comprese le librerie usate dalle tue dipendenze — possono lanciare nuovi errori, e la ricca complessità delle configurazioni degli utenti nel mondo reale può rivelare modalità di guasto che non erano visibili durante lo sviluppo o i test. Il codice di gestione degli errori negli esempi precedenti include sempre un caso predefinito per gestire gli errori che non hanno una clausola `catch` specifica.

La maggior parte del codice Swift non specifica il tipo degli errori che lancia. Tuttavia, potresti limitare il codice a lanciare errori di un solo tipo specifico nei seguenti casi particolari:

* Quando esegui codice su un sistema embedded che non supporta l'allocazione dinamica della memoria. Lanciare un'istanza di `any Error` o di un altro tipo protocollo boxed richiede di allocare memoria in fase di esecuzione per memorizzare l'errore. Al contrario, lanciare un errore di un tipo specifico permette a Swift di evitare l'allocazione sullo heap per gli errori.
* Quando gli errori sono un dettaglio di implementazione di una qualche unità di codice, come una libreria, e non fanno parte dell'interfaccia di quel codice. Poiché gli errori provengono solo dalla libreria, e non da altre dipendenze o dai client della libreria, puoi stilare un elenco esaustivo di tutti i possibili fallimenti. E poiché questi errori sono un dettaglio di implementazione della libreria, vengono sempre gestiti all'interno di quella libreria.
* Nel codice che si limita a propagare errori descritti da parametri generici, come una funzione che accetta un argomento closure e propaga tutti gli errori provenienti da quella closure. Per un confronto tra la propagazione di un tipo di errore specifico e l'uso di `rethrows`, vedi [Funzioni e metodi rethrowing](/riferimento-del-linguaggio/dichiarazioni.md#funzioni-e-metodi-rethrowing).

Per esempio, considera del codice che riassume delle valutazioni e usa il seguente tipo di errore:

```swift
enum StatisticsError: Error {
    case noRatings
    case invalidRating(Int)
}
```

Per specificare che una funzione lancia come errori solo valori `StatisticsError`, scrivi `throws(StatisticsError)` invece del solo `throws` quando dichiari la funzione. Questa sintassi è chiamata anche *typed throws* (throws tipizzato) perché scrivi il tipo di errore dopo `throws` nella dichiarazione. Per esempio, la funzione seguente lancia come errori valori `StatisticsError`.

```swift
func summarize(_ ratings: [Int]) throws(StatisticsError) {
    guard !ratings.isEmpty else { throw .noRatings }

    var counts = [1: 0, 2: 0, 3: 0]
    for rating in ratings {
        guard rating > 0 && rating <= 3 else { throw .invalidRating(rating) }
        counts[rating]! += 1
    }

    print("*", counts[1]!, "-- **", counts[2]!, "-- ***", counts[3]!)
}
```

Nel codice qui sopra, la funzione `summarize(_:)` riassume un elenco di valutazioni espresse su una scala da 1 a 3. Questa funzione lancia un'istanza di `StatisticsError` se l'input non è valido. Entrambi i punti del codice qui sopra che lanciano un errore omettono il tipo dell'errore perché il tipo di errore della funzione è già definito. Puoi usare la forma breve, `throw .noRatings`, invece di scrivere `throw StatisticsError.noRatings` quando lanci un errore in una funzione come questa.

Quando scrivi un tipo di errore specifico all'inizio della funzione, Swift verifica che tu non lanci altri errori. Per esempio, se provassi a usare `VendingMachineError` degli esempi precedenti di questo capitolo nella funzione `summarize(_:)` qui sopra, quel codice produrrebbe un errore in fase di compilazione.

Puoi chiamare una funzione che usa il typed throws dall'interno di una normale funzione che lancia errori:

```swift
func someThrowingFunction() throws {
    let ratings = [1, 2, 3, 2, 2, 1]
    try summarize(ratings)
}
```

Il codice qui sopra non specifica un tipo di errore per `someThrowingFunction()`, quindi lancia `any Error`. Potresti anche scrivere esplicitamente il tipo di errore come `throws(any Error)`; il codice seguente è equivalente al codice qui sopra:

```swift
func someThrowingFunction() throws(any Error) {
    let ratings = [1, 2, 3, 2, 2, 1]
    try summarize(ratings)
}
```

In questo codice, `someThrowingFunction()` propaga tutti gli errori lanciati da `summarize(_:)`. Gli errori di `summarize(_:)` sono sempre valori `StatisticsError`, che è anche un errore valido che `someThrowingFunction()` può lanciare.

Proprio come puoi scrivere una funzione che non restituisce mai con un tipo di ritorno `Never`, puoi scrivere una funzione che non lancia mai con `throws(Never)`:

```swift
func nonThrowingFunction() throws(Never) {
  // ...
}
```

Questa funzione non può lanciare errori perché è impossibile creare un valore di tipo `Never` da lanciare.

Oltre a specificare il tipo di errore di una funzione, puoi anche scrivere un tipo di errore specifico per un'istruzione `do`-`catch`. Per esempio:

```swift
let ratings = []
do throws(StatisticsError) {
    try summarize(ratings)
} catch {
    switch error {
    case .noRatings:
        print("No ratings available")
    case .invalidRating(let rating):
        print("Invalid rating: \(rating)")
    }
}
// Stampa "No ratings available".
```

In questo codice, scrivere `do throws(StatisticsError)` indica che l'istruzione `do`-`catch` lancia come errori valori `StatisticsError`. Come le altre istruzioni `do`-`catch`, la clausola `catch` può gestire ogni possibile errore oppure propagare gli errori non gestiti affinché li gestisca un qualche ambito circostante. Questo codice gestisce tutti gli errori, usando un'istruzione `switch` con un caso per ciascun valore dell'enumerazione. Come le altre clausole `catch` prive di pattern, la clausola corrisponde a qualsiasi errore e associa l'errore a una costante locale chiamata `error`. Poiché l'istruzione `do`-`catch` lancia valori `StatisticsError`, `error` è un valore di tipo `StatisticsError`.

La clausola `catch` qui sopra usa un'istruzione `switch` per confrontare e gestire ciascun possibile errore. Se provassi ad aggiungere un nuovo caso a `StatisticsError` senza aggiornare il codice di gestione degli errori, Swift ti darebbe un errore perché l'istruzione `switch` non sarebbe più esaustiva. Per una libreria che cattura tutti i propri errori, potresti usare questo approccio per garantire che a ogni nuovo errore corrisponda del nuovo codice per gestirlo.

Se una funzione o un blocco `do` lancia errori di un solo tipo, Swift inferisce che questo codice sta usando il typed throws. Usando questa sintassi più breve, potresti scrivere l'esempio `do`-`catch` qui sopra come segue:

```swift
let ratings = []
do {
    try summarize(ratings)
} catch {
    switch error {
    case .noRatings:
        print("No ratings available")
    case .invalidRating(let rating):
        print("Invalid rating: \(rating)")
    }
}
// Stampa "No ratings available".
```

Anche se il blocco `do`-`catch` qui sopra non specifica quale tipo di errore lancia, Swift inferisce che lancia `StatisticsError`. Puoi scrivere esplicitamente `throws(any Error)` per evitare che Swift inferisca il typed throws.

## Specificare azioni di pulizia <a href="#specificare-azioni-di-pulizia" id="specificare-azioni-di-pulizia"></a>

Usi un'istruzione `defer` per eseguire un insieme di istruzioni subito prima che l'esecuzione del codice lasci il blocco di codice corrente. Questa istruzione ti permette di eseguire qualsiasi pulizia necessaria che deve essere eseguita indipendentemente da *come* l'esecuzione lascia il blocco di codice corrente — sia che lo lasci perché è stato lanciato un errore sia a causa di un'istruzione come `return` o `break`. Per esempio, puoi usare un'istruzione `defer` per garantire che i descrittori di file vengano chiusi e che la memoria allocata manualmente venga liberata.

Un'istruzione `defer` rinvia l'esecuzione finché non si esce dall'ambito corrente. Questa istruzione è costituita dalla parola chiave `defer` e dalle istruzioni da eseguire in seguito. Le istruzioni rinviate non possono contenere alcun codice che trasferirebbe il controllo al di fuori delle istruzioni, come un'istruzione `break` o `return`, né lanciare un errore. Le azioni rinviate vengono eseguite nell'ordine inverso rispetto a quello in cui sono scritte nel tuo codice sorgente. Cioè, il codice della prima istruzione `defer` viene eseguito per ultimo, il codice della seconda istruzione `defer` viene eseguito come penultimo, e così via. L'ultima istruzione `defer` nell'ordine del codice sorgente viene eseguita per prima.

```swift
func processFile(filename: String) throws {
    if exists(filename) {
        let file = open(filename)
        defer {
            close(file)
        }
        while let line = try file.readline() {
            // Lavora con il file.
        }
        // close(file) viene chiamata qui, alla fine dell'ambito.
    }
}
```

L'esempio qui sopra usa un'istruzione `defer` per garantire che alla funzione `open(_:)` corrisponda una chiamata a `close(_:)`.

Puoi usare un'istruzione `defer` anche quando non è coinvolto alcun codice di gestione degli errori. Per maggiori informazioni, vedi [Azioni rinviate](/guida-al-linguaggio/flusso-di-controllo.md#azioni-rinviate).
