Sobes.tech
Middle

Vai vienmēr ir jānorāda `self` parametrs slēdzienos?

sobes.tech AI

Atbilde no AI

Nē, ne vienmēr.

Ir nepieciešams skaidri norādīt self slēdžos tikai šādos gadījumos:

  1. Nepilnīgajos (non-escaping) slēdžos: Tas ir kompilatora prasība skaidri norādīt self aizķeršanu. Lai arī tehniski aizķeršana pastāv, tā notiek funkcijas iekšienē un nerada stipru atsauču ciklus.
  2. Izlidojošajos (escaping) slēdžos, kad self aizķeršana ir pēc noklusējuma (implicit capture): Ja slēdzis iziet ārpus funkcijas, kurā tas tika deklarēts (piemēram, tiek nodots uz asīnhronu operāciju, tiek saglabāts īpašībā utt.), un jūs self aizķeršanu veicat neizteiksmīgi, kompilators pieprasīs skaidri norādīt self, lai izvairītos no potenciāla stipru atsauču cikla.

Visos citos gadījumos (piemēram, izmantojot [weak self] vai [unowned self] sarakstu) self norādīšana nav nepieciešama, jo īpašumtiesību attiecības ir skaidri kontrolētas.

Piemērs:

class MyClass {
    var value = 10

    func doSomething() {
        // Neizlidojošais slēdzis - nepieciešams `self`
        UIView.animate(withDuration: 0.3) {
            self.value = 20
        }
    }

    func fetchData(completion: @escaping (Result<String, Error>) -> Void) {
        // Izlidojošais slēdzis ar neizteiksmīgu `self` aizķeršanu - nepieciešams `self`
        // Tas var novest pie potenciāla stipru atsauču cikla, ja netiek izmantots `[weak self]`
        someAsyncOperation { data, error in
            if let data = data {
                // Nepieciešams `self`, izmantojot neizteiksmīgu aizķeršanu
                self.processData(data)
                completion(.success("Data processed"))
            } else if let error = error {
                completion(.failure(error))
            }
        }
    }

    func drošiFetchData(completion: @escaping (Result<String, Error>) -> Void) {
         // Izlidojošais slēdzis ar skaidru `[weak self]` aizķeršanu - `self?` ir opcionalais un neprasa `self.` priekšsaukumu
        someAsyncOperation { [weak self] data, error in
            guard let self = self else { return } // `self` tiek atvērts kā opcionalais

            if let data = data {
                self.processData(data) // `self.` nav nepieciešams
                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) {
    // Asinhronās operācijas imitācija
    DispatchQueue.global().asyncAfter(deadline: .now() + 1) {
        completion("Some data", nil)
    }
}