Назад к вопросам
Middle
147
questionbank
Расскажи о capture list в Swift.
Sobes Copilot
Получайте ответы в реальном времени
Ответ от нейросети
sobes.tech AI
Capture list в Swift используется для явного управления захватом переменных замыканиями (closures). Это позволяет избежать сильных циклов ссылок, особенно при работе с self в замыканиях, которые используются внутри классов. Основные типы захвата: weak и unowned.
| Тип захвата | Описание | Когда использовать |
|---|---|---|
weak |
Захватывает переменную как опционал, не увеличивая счетчик ссылок. Её значение может стать nil. |
Когда объект замыкания может пережить захватываемый объект. |
unowned |
Захватывает переменную без увеличения счетчика ссылок, но считается, что захватываемый объект будет жив, пока существует замыкание. Не опционал. | Когда объект замыкания и захватываемый объект имеют одинаковое время жизни, и захватываемый объект не будет nil до завершения замыкания. |
Синтаксис capture list:
{ [capture list] (parameters) -> returnType in
// code
}
Пример использования 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("Value is now \(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 не требуется в этом случае, так как button существует, пока существует 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("Initial value was \(initialValue)") // initialValue сохраняет свое значение
return currentValue
}
}
let incrementer = createIncrementer(initialValue: 5)
print(incrementer()) // Output: Initial value was 5, then 6
print(incrementer()) // Output: Initial value was 5, then 7