Sobes.tech
Middle

Ispričaj o capture list u Swift-u.

sobes.tech АИ

Одговор од АИ

У Swift-у се користи capture list за јасно управљање хватањем променљивих у затворима (closures). Ово помаже у избегавању јаких циклуса референци, посебно када се ради са self унутар затвора који се користи у класама. Главне врсте хватања су: weak и unowned.

Тип хватања Опис Када користити
weak Хвата променљиву као опционал, без повећања броја референци. Њена вредност може постати nil. Када објекат затвора може преживети у捕љени објекат.
unowned Хвата променљиву без повећања броја референци, али се претпоставља да ће捕љени објекат живети док постоји затвор. Нема опционал. Када затвор и捕љени објекат имају исто време живота, и捕љени објекат неће постати nil пре завршетка затвора.

Синтакса capture list:

{ [capture list] (параметри) -> повратни тип in
    // код
}

Пример употребе weak self:

class MyClass {
    var value = 0

    func doSomethingLater() {
        DispatchQueue.main.asyncAfter(deadline: .now() + 1) { [weak self] in
            guard let self = self else { return } // Провера на `nil`
            self.value += 1
            print("Вредност је сада \(self.value)")
        }
    }
}

Пример употребе unowned self:

class ViewController: UIViewController {
    var button: UIButton!

    override func viewDidLoad() {
        super.viewDidLoad()
        button = UIButton(type: .system)
        button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
    }

    @objc func buttonTapped() {
        // unowned self није потребан у овом случају, јер постоји док постоји ViewController.
        // Али ако затвор може преживети ViewController, unowned би био прикладан ако смо сигурни
        // да self неће постати `nil`.
        let action = { [unowned self] in
             self.view.backgroundColor = .blue
        }
        action()
    }
}

Могу се у捕љати не само self, већ и друге променљиве доступне у затвору. На пример, да сачувате вредност променљиве у тренутку креирања затвора:

func createIncrementer(initialValue: Int) -> () -> Int {
    var currentValue = initialValue
    return { [initialValue] in // Хвата initialValue по вредности
        currentValue += 1
        print("Почетна вредност била је \(initialValue)") // initialValue чува своју вредност
        return currentValue
    }
}

let incrementer = createIncrementer(initialValue: 5)
print(incrementer()) // Излаз: Почетна вредност била је 5, затим 6
print(incrementer()) // Излаз: Почетна вредност била је 5, затим 7