Sobes.tech
Middle+

Da li je uvek potrebno koristiti weak ili unowned u Capture List?

sobes.tech АИ

Одговор од АИ

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

weak и unowned се користе за спречавање циклуса јаких референци (retain cycles) у затварачу, када затварач држи јаку референцу на објекат, а објекат такође држи јаку референцу на затварач.

weak или unowned треба користити када затварач заузима јаку референцу на self или други референтни тип, и постоји вероватноћа да ће настати циклус јаких референци.

Ситуације када није потребно користити weak/unowned:

  • Затварач заузима типове вредности (структуре, енамуа, кортежи). Они се копирају приликом заузимања, и циклуси јаких референци не настају.
  • Затварач заузима референтни тип, али не постоји двосмерни јак циклус. На пример, ако се затварач креира локално унутар методе и не чува се од стране објекта на који се односи.
  • Затварач има кратак век трајања и биће извршен пре него што објекат на који се односи буде ослобођен. На пример, затварач који се преноси као Completion Handler умето умето и одмах се извршава.

Избор између weak и unowned:

  • weak: користи се када заузети објекат може постати nil у било ком тренутку пре извршења затварача. Референца је као опциони (ObjectType?). Потребна је провера на nil пре коришћења.
  • unowned: користи се када је познато да ће заузети објекат увек постојати у тренутку извршења затварача. Референца није опционирана (ObjectType). Нема потребе за провером на nil. Коришћење unowned за објекат који постане nil довешће до грешке (runtime error).
// Пример, када није потребно `weak`/`unowned` (загрљај структуре)
struct MyStruct {
    var value: Int
}

let myStruct = MyStruct(value: 10)
let closure = {
    print(myStruct.value) // копија myStruct
}
closure()

// Пример, када није потребно `weak`/`unowned` (локални затварач)
class MyClass {
    func doSomething() {
        let localValue = 5
        let localClosure = {
            print(self.description) // заузима self, али затварач се не чува у MyClass
        }
        localClosure()
    }

    var description: String {
        return "Објекат MyClass"
    }
}

let myObject = MyClass()
myObject.doSomething()

// Пример, када је потребан `weak` (може бити `nil`)
class AsyncOperation {
    var completionHandler: (() -> Void)?

    func performOperation() {
        DispatchQueue.global().async {
            print("Операција завршена")
            self.completionHandler?()
        }
    }

    deinit {
        print("AsyncOperation је ослобођен")
    }
}

class ViewController {
    var op: AsyncOperation?

    func setupOperation() {
        op = AsyncOperation()
        op?.completionHandler = { [weak self] in
            guard let self = self else { return }
            print("Завршни руковаоци у ViewController-у: \(self)")
        }
    }

    deinit {
        print("ViewController је ослобођен")
    }
}

// Пример, када је потребан `unowned` (гарантовано постоји)
class Button {
    var action: (() -> Void)?

    func tap() {
        action?()
    }

    deinit {
        print("Button је ослобођен")
    }
}

class ViewControllerWithButton {
    var button: Button

    init() {
        button = Button()
        button.action = { [unowned self] in
            print("Тастер је притиснут у ViewControllerWithButton-у: \(self)")
        }
    }

    deinit {
        print("ViewControllerWithButton је ослобођен")
    }
}