Sobes.tech
Middle

Разкажи за списъка с каптури в Swift.

sobes.tech AI

Отговор от AI

В 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