Замыкание с [unowned self] падает после закрытия экрана — исправьте
Этот контроллер хранит сетевой клиент, который вызывает колбэк по завершении. Он захватывает [unowned self], чтобы избежать цикла удержания. Когда пользователь закрывает экран до завершения запроса, приложение падает.
Ограничения:
- Оставьте замыкание; не делайте захват сильным (это приведёт к утечке).
- Исправление должно сделать вызов после исчезновения
selfбезопасным no-op.
final class ProfileViewController: UIViewController {
let client = APIClient()
func load() {
client.fetchProfile { [unowned self] profile in
self.render(profile) // падает после pop
}
}
func render(_ profile: Profile) { /* ... */ }
}
Найдите и исправьте ошибку.
Замыкание переживает self, поэтому его unowned-ссылка смотрит в мёртвую память и вызов падает — он зря полагал, что self его переживёт. Захватывайте [weak self] с guard let self, тогда мёртвый self — безопасный no-op.
- ✗Принимают падение из-за висячего указателя за цикл удержания
- ✗Винят поток, а не ошибочное предположение
unownedо времени жизни - ✗Переходят на сильный захват, что снова создаёт утечку
- →Когда
[unowned self]действительно верный выбор для замыкания? - →Почему
guard let selfделает вызов на мёртвомselfбезопасным no-op?
unowned не обнуляется: он предполагает, что объект живёт дольше замыкания. Здесь запрос завершается уже после pop, self освобождён, и обращение к unowned читает мёртвую память — отсюда EXC_BAD_ACCESS. Меняем на [weak self] и разворачиваем через guard let self:
func load() {
client.fetchProfile { [weak self] profile in
guard let self else { return } // мёртвый self -> безопасный выход
self.render(profile)
}
}
weak держит ссылку optional и обнуляет её при освобождении self, поэтому после pop замыкание просто ничего не делает вместо падения. Сильный захват тоже убрал бы падение, но вернул бы утечку — контроллер жил бы, пока жив колбэк.