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...
}
}