Sobes.tech
Middle

Da li je uvek potrebno koristiti weak ili unowned u listi hvatanja?

sobes.tech АИ

Одговор од АИ

Не, не увек увек.

Користимо weak или unowned у Capture List-у за спречавање циклуса задржавања.

Циклус задржавања настаје када два или више објеката јако се позивају, спречавајући ослобађање меморије.

Користити weak или unowned треба када затварање јако се позива на self (или другу променљиву инстанце класе/актора), и уједно self (или други објекат) има јаку референцу на то затварање.

Примери ситуација када је то потребно:

  • Асиминроне операције (мрежни захтеви, обрада података)
  • Обсервер модел
  • Анимациони блокови
  • Dispatch редови

Ако затварање не заузима self (или другу променљиву класе/актора која има јаку референцу на затварање), или заузима структурне типове/енумерације, коришћење weak или unowned није потребно.

Разлика између weak и unowned:

Тип Опис Када користити
weak Слаба (опциони) референца. Може постати nil. Када је животни циклус затварања краћи или једнак животном циклусу заузетог објекта, и објекат може постати nil пре завршетка затварања.
unowned Неосновна (неопциони) референца. Не може постати nil. Када је животни циклус затварања краћи или једнак животном циклусу заузетог објекта, и гарантовано да ће објекат постојати до завршетка затварања. Ако објекат буде ослобођен пре извршења затварања, доћи ће до пада (unowned референца на деаллокирану инстанцу).

Пример коришћења weak у Capture List:

class MyClass {
    var name: String = "Test"

    func performAsyncOperation() {
        DispatchQueue.global().async { [weak self] in
            guard let self = self else {
                return
            }
            print("Операција завршена за \(self.name)")
        }
    }

    deinit {
        print("MyClass деаллокиран")
    }
}

Пример коришћења unowned у Capture List:

class ViewController {
    var dismissButton: UIButton!

    func setupButton() {
        dismissButton.addTarget(self, action: #selector(dismiss), for: .touchUpInside)
        // Овај пример показује да `self` (ViewController) живи дуже или једнако као и акција дугмета.
        // Target-action није затварање, али илуструје концепт unowned у случају јаког циклуса задржавања.
        // Ако би то било затварање, нпр. у handler-у UIControl.Event,
        // и ViewController је гарантовано постоји током притиска на дугме:
        // dismissButton.addAction(UIAction { [unowned self] _ in
        //     self.dismiss(animated: true, completion: nil)
        // }, for: .touchUpInside)
    }

    @objc func dismiss() {
        // Затварање view контролера
    }
}

Ако затварање не ствара циклус задржавања, коришћење weak или unowned није неопходно и чак може довести до непотребних провера (у случају weak) или потенцијалних пада (у случају unowned).

На пример, затварање које не заузима self или други објекат, који има јаку референцу на затварање:

func fetchData(completion: @escaping (Data) -> Void) {
    URLSession.shared.dataTask(with: URL(string: "...")!) { data, response, error in
        guard let data = data else { return }
        // Овде нема заузимања `self` или других објеката који могу изазвати циклус задржавања.
        completion(data)
    }.resume()
}

У овом случају, [weak self] или [unowned self] у Capture List-у нису потребни.