Sobes.tech
Middle

Da li je uvek potrebno navesti parametar `self` u zatvaranjima?

sobes.tech АИ

Одговор од АИ

Не, не увек.

Необходимо је јасно назначити 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 сигурноFetchData(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)
    }
}