После входа экземпляра класса в deinit когда ARC освобождает его сильные stored-свойства?
Сильные stored-свойства экземпляра остаются доступными и удерживают свои объекты во время выполнения тела deinit. После завершения тела deinit ARC разрушает хранилище экземпляра и освобождает эти сильные ссылки; если какая-либо из них была последней, связанный объект может быть уничтожен в этот момент.
ARC автоматизировал операции retain и release, которые при ручном управлении памятью требовалось расставлять самостоятельно. При этом Swift сохранил детерминированную модель подсчёта ссылок: уничтожение объекта начинается, когда исчезает его последняя сильная ссылка.
Разделение вызова deinit и последующего разрушения хранилища позволяет коду deinit корректно выполнить финализацию, пока состояние экземпляра ещё доступно.
Неверное предположение, что stored-свойства уже освобождены к моменту входа в deinit, приводит к обращениям к недоступному состоянию или к преждевременной ручной очистке ресурсов. Обратная ошибка — считать, что strong-свойства освобождаются сразу после начала deinit, — может привести к неправильным ожиданиям относительно порядка deinit связанных объектов.
Важно отличать сильные stored-свойства от weak и unowned ссылок: слабая ссылка не удерживает объект, а невладеющая ссылка не увеличивает его счётчик сильных ссылок.
При обнаружении последней сильной ссылки ARC запускает разрушение экземпляра. Сначала выполняется тело его deinit, поэтому сильные stored-свойства ещё существуют, а объекты, на которые они ссылаются, всё ещё удерживаются этим экземпляром.
После завершения deinit ARC разрушает stored-свойства и освобождает их значения. Для свойства классового типа это означает уменьшение счётчика сильных ссылок на связанный объект. Если счётчик становится равен нулю, его deinit может быть вызван непосредственно в ходе такого разрушения.
В теле deinit Owner свойство child ещё доступно. После завершения deinit Owner его сильная ссылка освобождается, поэтому затем становится возможным вызов Child.deinit, если других сильных владельцев нет. Точный момент машинных retain/release-операций может оптимизироваться компилятором, но семантически нельзя использовать объект после завершения его deinit.
Не следует вручную обнулять сильные свойства только ради их освобождения: это меняет состояние объекта и может вызвать deinit вложенного объекта ещё внутри тела deinit. Обычно достаточно позволить ARC разрушить хранилище естественным образом.
В менеджере ресурсов stored-свойство connection содержит объект соединения, а deinit менеджера записывает в журнал идентификатор соединения. Если обнулить connection в начале deinit, соединение может закрыться до записи в журнал, а его deinit выполнится в неожиданной точке.
Вариант с ручным обнулением даёт раннее освобождение ресурса, но усложняет порядок уничтожения и может вызвать побочные эффекты прямо внутри deinit. Вариант с обычным завершением deinit сохраняет свойство доступным для финализации и оставляет освобождение под контролем ARC.
Практическое решение — не изменять сильные stored-свойства без необходимости, а явно освобождать ресурс только тогда, когда раннее освобождение действительно является частью контракта класса. Это делает порядок завершения предсказуемее и уменьшает риск обращения к уже освобождённому связанному состоянию.
1. Может ли stored-свойство быть доступно в deinit, если оно содержит optional?
Да. Если это сильное optional-свойство, его текущее значение доступно в deinit. При значении nil освобождать нечего; при наличии экземпляра он продолжает удерживаться до разрушения самого свойства или до явного присваивания другого значения.
2. Освобождаются ли weak-свойства после deinit так же, как strong-свойства?
Нет. Weak-ссылка не владеет объектом и не удерживает его до разрушения контейнера. При уничтожении объекта runtime обнуляет связанные weak-ссылки, поэтому в deinit контейнера weak-свойство может уже быть nil, даже если соответствующее хранилище самого контейнера ещё существует.
3. Можно ли полагаться на порядок deinit объектов, хранимых в нескольких strong-свойствах?
Нельзя строить прикладную логику на порядке уничтожения независимых свойств. ARC освобождает хранилище в рамках правил разрушения объекта, но код должен быть корректен независимо от порядка, если свойства не образуют явно заданную зависимость. Нужный порядок следует выражать явным методом завершения или протоколом владения, а не косвенно ожидать его от deinit.