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