Sobes.tech
Junior

Cos'è una chiusura?

sobes.tech AI

Risposta dell'AI

La chiusura (closure) in Swift è un blocco autonomo di funzionalità ({}) che può essere passato e utilizzato nel codice. Le chiusure possono catturare e memorizzare riferimenti a qualsiasi costante o variabile del contesto in cui sono definite.

Esempi di utilizzo:

  • Come argomenti di funzioni (ad esempio, gestori di completamento).
  • Per definire comportamenti durante l'iterazione di collezioni (ad esempio, usando metodi map, filter, reduce, sorted).
  • Per l'esecuzione differita di codice.

Sintassi:

// Sintassi di base
{ (parametri) -> tipoDiRitorno in
    dichiarazioni
}

// Esempio di chiusura che accetta un Int e restituisce una String
let integerToString: (Int) -> String = { (number: Int) -> String in
    return "Numero: \(number)"
}

Caratteristiche:

  • Cattura automatica delle variabili.
  • Possibilità di definire chiusure senza specificare esplicitamente i tipi di parametri e di ritorno (sugar sintattico).
  • Uso di nomi abbreviati per i parametri ($0, $1, ecc.).
  • Sintassi di chiusura con trailing closure.

Cattura di variabili:

Una chiusura può catturare variabili dal suo ambiente. Per impostazione predefinita, la cattura avviene per riferimento. Se una chiusura viene usata dopo che la variabile originale è uscita dal contesto, mantiene comunque l'accesso ad essa.

func makeIncrementer(forIncrement amount: Int) -> () -> Int {
    var runningTotal = 0 // Variabile dal contesto esterno
    let incrementer: () -> Int = { // Chiusura
        runningTotal += amount // Cattura runningTotal e amount
        return runningTotal
    }
    return incrementer
}

let incrementByTen = makeIncrementer(forIncrement: 10)
print(incrementByTen()) // Output: 10
print(incrementByTen()) // Output: 20

Liste di cattura (Capture Lists):

Vengono usate per indicare esplicitamente come le variabili devono essere catturate - per valore o per riferimento, e per evitare cicli di riferimenti forti (retain cycles).

class MyClass {
    var value = 0

    lazy var myClosure: () -> Void = { [self, value] in // Cattura self per riferimento, value per valore
        print("Valore di self.value: \(self.value)")
        print("Valore catturato: \(value)")
    }

    deinit {
        print("Istanza di MyClass liberata")
    }
}

Per evitare cicli di riferimenti forti durante la cattura di oggetti di classi, si utilizza la sintassi [weak self] o [unowned self].

class ViewController {
    var dataFetcher: DataFetcher?

    func fetchData() {
        dataFetcher?.fetch { [weak self] result in // Cattura debole di self
            guard let self = self else { return } // Verifica dell'esistenza di self
            // Elaborazione del risultato
        }
    }
}

class DataFetcher {
    var completionHandler: ((Result<String, Error>) -> Void)?

    func fetch(completion: @escaping (Result<String, Error>) -> Void) {
        self.completionHandler = completion
        // Operazione asincrona...
    }
}