У ViewModel не вызывается deinit после закрытия экрана
Экран ленты на iOS:
final class FeedViewModel {
private let service: FeedService
private var cache: [Post] = []
var onUpdate: (([Post]) -> Void)?
func subscribe() {
service.observe { posts in
self.cache = posts
self.onUpdate?(posts)
}
}
}
Сервис хранит переданное замыкание у себя, пока подписка активна. Экран закрывают, но брейкпоинт в deinit у ViewModel не срабатывает, а обновления продолжают приходить.
В чём причина?
- Замыкание, которое удерживает сервис, сильно захватывает self — возникает цикл сильных ссылок, нужен захват [weak self]
- deinit не вызывается у классов с активными асинхронными подписками — это ожидаемое поведение среды выполнения, объект освободится позже сам
- Причина в том, что onUpdate объявлено как var: опциональные замыкания всегда удерживают своего владельца
- Объект не освобождается, потому что класс не наследуется от NSObject и не отслеживается механизмом подсчёта ссылок
