Ответ
Capture list (список захвата) — это синтаксическая конструкция в Swift, которая явно определяет, как замыкание захватывает переменные и константы из окружающего контекста. Её основная цель — управление памятью и предотвращение сильных циклов ссылок (retain cycles).
Базовый синтаксис: { [capture_specification] in ... }
Пример проблемы и решения:
class ViewController {
var counter = 0
var closure: (() -> Void)?
func setupProblem() {
// ПРОБЛЕМА: Сильный цикл! Замыкание сильно захватывает `self`,
// а `self` сильно хранит замыкание в свойстве `closure`.
closure = {
self.counter += 1 // Сильный захват self
}
}
func setupSolution() {
// РЕШЕНИЕ: Используем capture list для слабого захвата.
closure = { [weak self] in
self?.counter += 1 // self теперь опциональный
}
}
}
Основные типы захвата в списке:
[weak object]: Захват слабой (weak) ссылки. Объект становится опциональным (T?) внутри замыкания. Используется для разрыва retain cycles.[unowned object]: Захват безусловной (unowned) ссылки. Предполагает, что объект не будет освобожден. Опасен, если предположение неверно.[variable = value]: Захват по значению (value capture). Фиксирует значение переменной на момент создания замыкания.var value = 10 let closure = { [capturedValue = value] in print(capturedValue) // Всегда напечатает 10, даже если внешняя `value` изменится } value = 20 closure() // Вывод: 10
Правило: Всегда используйте capture list ([weak self] или [unowned self]), когда замыкание, хранимое в свойстве класса, захватывает self.
Ответ 18+ 🔞
А, capture list, ёпта! Это ж та самая штука, которая от циклических ссылок спасает, а то приложение твоё накрывается медным тазом, и ты потом полгода ищешь, где память течёт, блядь.
Смотри, представь себе классическую пиздецовую ситуацию. Есть у тебя ViewController, здоровый такой мужик. И есть у него замыкание, этакая хитрая жопа, которая внутри себя self использует.
class ViewController {
var counter = 0
var closure: (() -> Void)? // Вот эта падла, хранитель замыкания
func setupProblem() {
// А вот и ПИЗДЕЦ, Карл! Смотри, что происходит:
closure = {
self.counter += 1 // Замыкание схватило self мертвой хваткой, как бульдог за яйца
}
}
}
Вот смотри на эту хуйню: self (то есть вьюконтроллер) крепко держит свойство closure. А closure, в свою очередь, внутри себя намертво вцепился в self. Они друг друга держат, обнялись, как два пидараса шерстяных, и никуда не отпускают. Это и есть retain cycle, сильный цикл ссылок. Память никогда не освободится, утечка, блядь! Приложение жрёт оперативку, как не в себя, и потом — бац! — креш. Удивление пиздец.
И что делать? А вот тут-то и выходит на сцену наш спаситель — capture list, список захвата, блядь! Чистая магия, чтобы разорвать эти ебучіе объятия.
func setupSolution() {
// РЕШЕНИЕ, наконец-то! Используем capture list.
closure = { [weak self] in // Сказали замыканию: "Хватай self СЛАБО, нежно!"
self?.counter += 1 // И теперь self — опциональный. Может и nil быть, если вьюконтроллера уже нет.
}
}
Вот видишь разницу? Мы в квадратных скобочках [weak self] дали команду: «Э, дружок-замыкание, хватай self, но только слабой ссылкой, не за душицу!». И теперь, если вьюконтроллер умрёт, замыкание не будет держать его на этом свете силой. self внутри станет nil, и всё, пипец, цикл разорван. Красота, бля!
А есть ещё, блядь, [unowned self]. Это как weak, только без страховки. Ты говоришь: «Да похуй, self точно будет жить, пока это замыкание живо!». И внутри замыкания self — не опциональный. Но если ты ошибся, и self таки умер раньше — приложение крашнется, когда замыкание попробует к нему обратиться. Овердохуища риска. Используй, только если на 146% уверен, как в том, что земля плоская.
Ну и фишка третья — захват по значению. Вообще огонь, блядь.
var value = 10
let closure = { [capturedValue = value] in // Захватили значение ВНЕШНЕЙ переменной на момент создания
print(capturedValue) // И теперь capturedValue — это константа 10, зафиксированная, блядь!
}
value = 20 // Внешней переменной похуй, она теперь 20
closure() // А тут выведет: 10. Потому что capturedValue — это снимок прошлого, как фотка.
Короче, правило жизни простое, запомни его, как «Отче наш»: всегда пиши [weak self] (или [unowned self], если совсем еблан), когда замыкание, которое живёт в свойстве класса (как наша closure), обращается к self. Иначе сам себя за ногу привяжешь, блядь, и будешь в памяти плавать, как Муму в том озере.