В Swift замыкания (closures) бывают либо неэкранирующими (по умолчанию), либо экранирующими, в зависимости от того, могут ли они пережить функцию, в которую они переданы.
Неэкранирующее замыкание выполняется в течение времени жизни функции, в которую оно передано. После возврата из функции замыкание исчезает.
self можно ссылаться неявноfunc performAction(closure: () -> Void) {
closure() // executed immediately, does not escape
}
Экранирующее замыкание помечается @escaping и может пережить функцию — оно может быть сохранено, выполнено позже или передано другой функции.
@escapingself обязательна, чтобы утечки памяти были заметныfunc fetchData(completion: @escaping () -> Void) {
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
completion() // called after function has returned
}
}
Поскольку экранирующие замыкания могут быть сохранены и вызваны позже, они захватывают и удерживают любые объекты, на которые ссылаются. Всегда используй список захвата (capture list), чтобы избежать retain-циклов:
fetchData { [weak self] in
self?.updateUI()
}
| Неэкранирующее | Экранирующее | |
|---|---|---|
| Переживает функцию | Нет | Да |
| Аннотация | Нет | @escaping |
Явное self | Опционально | Обязательно |
Неуходящие замыкания позволяют использовать неявные ссылки на self, потому что компилятор может гарантировать, что замыкание будет выполнено в течение жизненного цикла функции, исключая риск циклических ссылок.
Новый — ещё не проверен сообществом
Вы