Sobes.tech
Middle

Винаги ли трябва да посочвате параметъра `self` в затварянията?

sobes.tech AI

Отговор от AI

Не, не винаги.

Необходимо е явно да се посочи self в затварящи функции само в следните случаи:

  1. В не-избягващи (non-escaping) затварящи функции: Това е изискване на компилатора за явно обозначаване на захвата self. Въпреки че захватът технически съществува, той се случва вътре във функция и не води до цикли от силни препратки.
  2. В излъчващи (escaping) затварящи функции при захват на self по подразбиране (implicit capture): Ако затварящата функция излиза извън обхвата на функцията, в която е обявена (например, се предава към асинхронна операция, се запазва в свойство и т.н.), и вие захващате self неявно, компилаторът ще изисква явно посочване на self за яснота на потенциален цикъл от силни препратки.

В останалите случаи (например, в излъчващи затварящи функции при използване на списък за захват [weak self] или [unowned self]) не е необходимо да се посочва self, тъй като отношението на собствеността е явно контролирано.

Пример:

class MyClass {
    var value = 10

    func doSomething() {
        // Неизлъчващо затваряне - изисква `self`
        UIView.animate(withDuration: 0.3) {
            self.value = 20
        }
    }

    func fetchData(completion: @escaping (Result<String, Error>) -> Void) {
        // Излъчващо затваряне с неявен захват `self` - изисква `self`
        // Може да доведе до потенциален цикъл от силни препратки, ако не се използва `[weak self]`
        someAsyncOperation { data, error in
            if let data = data {
                // Изисква `self` при използване на неявен захват
                self.processData(data)
                completion(.success("Data processed"))
            } else if let error = error {
                completion(.failure(error))
            }
        }
    }

    func safelyFetchData(completion: @escaping (Result<String, Error>) -> Void) {
         // Излъчващо затваряне с явно захващане `[weak self]` - `self?` е опционално и не изисква явен `self.` пред обръщението
        someAsyncOperation { [weak self] data, error in
            guard let self = self else { return } // Разгъване на `self` като опционално

            if let data = data {
                self.processData(data) // Не е необходимо `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) {
    // Имитация на асинхронна операция
    DispatchQueue.global().asyncAfter(deadline: .now() + 1) {
        completion("Some data", nil)
    }
}