Sobes.tech
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:

  1. Ne-išsaugomuose (non-escaping) uždarymuose: Tai yra kompiliatoriaus reikalavimas aiškiai pažymėti self užklausą. Nors techninis užklausos egzistavimas, jis vyksta funkcijos viduje ir nesukelia stiprių nuorodų ciklų.
  2. Išsaugomuose (escaping) uždarymuose, kai self už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žklausiate self neaiškiai, kompiliatorius reikalauja aiškaus self nurodymo, 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)
    }
}