Ce este o închidere?
sobes.tech AI
Răspuns de la AI
În Swift, închiderea (closure) este un bloc autonom de funcționalitate ({}), care poate fi transmis și utilizat în cod. Închiderea poate captura și stoca referințe la orice constante și variabile din contextul în care sunt definite.
Exemple de utilizare:
- Ca argumente ale funcțiilor (de exemplu, manipulatoare de finalizare).
- Pentru a defini comportamentul în timpul enumerării colecțiilor (de exemplu, folosind metodele
map,filter,reduce,sorted). - Pentru executarea întârziată a codului.
Sintaxă:
// Sintaxă de bază
{ (parametri) -> tipDeReturnare in
declarații
}
// Exemplu de închidere care acceptă un Int și returnează un String
let integerToString: (Int) -> String = { (number: Int) -> String in
return "Număr: \(number)"
}
Caracteristici:
- Capturare automată a variabilelor.
- Posibilitatea de a defini închideri fără a specifica explicit tipurile parametrilor și valorii de returnare (zahăr sintactic).
- Utilizarea numelor scurte pentru parametri ($0, $1, etc.).
- Sintaxă de închidere cu trailing closure.
Capturarea variabilelor:
O închidere poate captura variabile din mediul său. În mod implicit, capturarea se face prin referință. Dacă o închidere este utilizată după ce variabila originală a ieșit din domeniu, ea păstrează totuși accesul la aceasta.
func makeIncrementer(forIncrement amount: Int) -> () -> Int {
var runningTotal = 0 // Variabilă din contextul extern
let incrementer: () -> Int = { // Închidere
runningTotal += amount // Capturează runningTotal și amount
return runningTotal
}
return incrementer
}
let incrementByTen = makeIncrementer(forIncrement: 10)
print(incrementByTen()) // Ieșire: 10
print(incrementByTen()) // Ieșire: 20
Liste de capturare (Capture Lists):
Sunt folosite pentru a indica explicit modul în care variabilele trebuie capturate - prin valoare sau prin referință, precum și pentru a evita ciclurile de referințe puternice (retain cycles).
class MyClass {
var value = 0
lazy var myClosure: () -> Void = { [self, value] in // Capturare a self prin referință, a value prin valoare
print("Valoarea self.value: \(self.value)")
print("Valoarea capturată: \(value)")
}
deinit {
print("Instanța MyClass a fost eliberată")
}
}
Pentru a evita ciclurile de referințe puternice la capturarea obiectelor de clase, se folosește sintaxa [weak self] sau [unowned self].
class ViewController {
var dataFetcher: DataFetcher?
func fetchData() {
dataFetcher?.fetch { [weak self] result in // Capturare slabă a self
guard let self = self else { return } // Verificare existență self
// Procesare rezultat
}
}
}
class DataFetcher {
var completionHandler: ((Result<String, Error>) -> Void)?
func fetch(completion: @escaping (Result<String, Error>) -> Void) {
self.completionHandler = completion
// Operație asincronă...
}
}