Закрытия (closures) в Swift — это самостоятельные блоки кода, которые могут захватывать и сохранять ссылки на переменные и константы из окружающего контекста. Они позволяют организовать callback'и, асинхронную обработку и хранить исполнение кода как значения переменных.
var counter = 0 let incrementer: () -> Void = { counter += 1 } incrementer() print(counter) // 1
[weak self], [unowned self]).self внутри closure.Чем отличается strong-capture от использования
[weak self]или[unowned self]в capture list closure? Чем это чревато?
Ответ:
Если вы не укажете [weak self] или [unowned self], closure по умолчанию захватит self по сильной ссылке, что приведет к retain cycle, если closure и self ссылаются друг на друга. [weak self] захватывает self по слабой ссылке (optional), [unowned self] — по неконтролируемой ссылке (non-optional). Неправильный выбор или отсутствие capture list приводит к утечкам памяти или крашам.
class Test { var closure: (() -> Void)? func setup() { closure = { [weak self] in self?.doWork() } } func doWork() { ... } }
История
Программист не использовал capture list в closure внутри UIViewController, который запускал асинхронную загрузку данных. В результате controller и его view не освобождались, что приводило к memory leak после закрытия (dismiss). Анализ инфраструктуры показал сотни "зависших" в памяти контроллеров.
История
Closure захватывал self с помощью [unowned self], но при этом жизненный цикл self завершался раньше closure. Получился краш при обращении к уже освобожденному объекту — приложение вылетало при попытке работы с self inside closure.
История
На проекте внутри вложенной closure захватили две переменные: одну по strong, вторую по weak. Оказалось, что weak-ссылка обнулялась слишком рано, и данные, необходимые для работы closure, были потеряны — баг проявился только в stress-test при нагрузке в многопоточной среде.