Sobes.tech
Middle

Kas on alati vaja märkida `self` parameeter sulgemistes?

sobes.tech AI

Vastus AI-lt

Ei, mitte alati.

On vaja selgelt märkida self sulgudes ainult järgmistes juhtudel:

  1. Mitte-escape (non-escaping) sulgudes: See on kompilaatori nõue selgelt märkida self haaramine. Kuigi haaramine on tehniliselt olemas, toimub see funktsiooni sees ega põhjusta tugevaid viiditsüklisid.
  2. Escape (väljuvad) sulgudes, kui self haaramine on vaikimisi (implicit capture): Kui sulg väljub funktsiooni piiridest, kus see oli deklareeritud (näiteks edastatakse asünkroonsele operatsioonile, salvestatakse omadusse jms), ja te haarate self-i ebamääraselt, nõuab kompilaator selget self märkust, et vältida potentsiaalseid tugevaid viiditsüklisid.

Kõik teised juhtumid (näiteks [weak self] või [unowned self] loeteluga) ei nõua self märkust, kuna omandi suhe on selgelt kontrollitud.

Näide:

class MyClass {
    var value = 10

    func doSomething() {
        // Mitte-escape sulg - nõutud `self`
        UIView.animate(withDuration: 0.3) {
            self.value = 20
        }
    }

    func fetchData(completion: @escaping (Result<String, Error>) -> Void) {
        // Escape sulg ebamäärase `self` haaramisega - nõutud `self`
        // Võib põhjustada tugeva viiditsüklilise olukorra, kui `[weak self]` ei kasutata
        someAsyncOperation { data, error in
            if let data = data {
                // Nõutud `self` ebamäärase haaramise korral
                self.processData(data)
                completion(.success("Data processed"))
            } else if let error = error {
                completion(.failure(error))
            }
        }
    }

    func turvaliseltFetchData(completion: @escaping (Result<String, Error>) -> Void) {
         // Escape sulg koos `[weak self]`-ga - `self?` on valikuline ja ei nõua `self.`-i enne kasutamist
        someAsyncOperation { [weak self] data, error in
            guard let self = self else { return } // Lahtivõtmine `self` valikulise

            if let data = data {
                self.processData(data) // Ei ole vaja `self.`
                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) {
    // Asünkroonne operatsioon
    DispatchQueue.global().asyncAfter(deadline: .now() + 1) {
        completion("Some data", nil)
    }
}