Sobes.tech
Junior

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