Middle
Ar visada reikia nurodyti `self` parametrą uždarymuose?
sobes.tech AI
Atsakymas iš AI
Ne, ne visada.
Reikia aiškiai nurodyti self uždarymuose tik šiais atvejais:
- Ne-išsaugomuose (non-escaping) uždarymuose: Tai yra kompiliatoriaus reikalavimas aiškiai pažymėti
selfužklausą. Nors techninis užklausos egzistavimas, jis vyksta funkcijos viduje ir nesukelia stiprių nuorodų ciklų. - Išsaugomuose (escaping) uždarymuose, kai
selfužklausimas yra numatytas (implicit capture): Jei uždarymas išlenda už funkcijos, kurioje jis buvo paskelbtas (pavyzdžiui, perduodamas į asinchroninę operaciją, saugomas savybėje ir t.t.), ir jūs užklausiateselfneaiškiai, kompiliatorius reikalauja aiškausselfnurodymo, kad būtų išvengta galimo stiprių nuorodų ciklo.
Visais kitais atvejais (pavyzdžiui, naudojant [weak self] arba [unowned self] sąrašą) self nurodymas nėra būtinas, nes nuosavybės santykis yra aiškiai kontroliuojamas.
Pavyzdys:
class MyClass {
var value = 10
func doSomething() {
// Ne-išsaugomas uždarymas - reikalingas `self`
UIView.animate(withDuration: 0.3) {
self.value = 20
}
}
func fetchData(completion: @escaping (Result<String, Error>) -> Void) {
// Išsaugomas uždarymas su neaiškiu `self` - reikalingas `self`
// Gali sukelti galimą stiprių nuorodų ciklą, jei nenaudojama `[weak self]`
someAsyncOperation { data, error in
if let data = data {
// Reikalingas `self` naudojant neaiškų užklausą
self.processData(data)
completion(.success("Data processed"))
} else if let error = error {
completion(.failure(error))
}
}
}
func saugiaiFetchData(completion: @escaping (Result<String, Error>) -> Void) {
// Išsaugomas uždarymas su aiškiu `[weak self]` užklausimu - `self?` yra pasirinktinė ir nereikalauja `self.` prieš kreipimąsi
someAsyncOperation { [weak self] data, error in
guard let self = self else { return } // Išskleidžiame `self` kaip pasirinktinį
if let data = data {
self.processData(data) // `self.` nereikalingas
completion(.success("Data processed"))
} else if let error = error {
completion(.failure(error))
}
}
}
private func processData(_ data: String) {
print("Processing \(data)")
}
}
func someAsyncOperation(completion: @escaping (String?, Error?) -> Void) {
// Asinchroninė operacija imitacija
DispatchQueue.global().asyncAfter(deadline: .now() + 1) {
completion("Some data", nil)
}
}