Сохраняет ли экземпляр класса время жизни после помещения в значение типа Any?
Да. Если значение типа Any содержит экземпляр класса, оно обычно владеет этим экземпляром сильной ссылкой, поэтому объект не деаллоцируется после исчезновения исходной сильной ссылки. Объект становится доступным для уничтожения, когда из Any удаляется это значение или оно заменяется другим.
Any появился как универсальный контейнер для значения произвольного типа, включая структуры, перечисления и экземпляры классов. Он решает задачу хранения разнородных значений без привязки к конкретному типу, но не отменяет правил управления временем жизни ссылочных объектов.
Swift сохраняет семантику владения при передаче значения в контейнер. Поэтому помещение объекта в Any не превращает ссылку в слабую и не передаёт управление временем жизни сборщику мусора.
Представим очередь событий типа [Any], куда временно помещаются объекты. Разработчик может считать, что после обнуления исходной переменной объект исчезнет, но элемент очереди продолжает содержать сильную ссылку.
Неверное ожидание приводит к росту удерживаемого графа объектов, задержке вызова deinit и увеличению пикового потребления памяти. Особенно опасно хранить в Any крупные объекты или структуры, которые сами содержат сильные ссылки.
При присваивании экземпляра класса значению типа Any контейнер сохраняет это значение с сильным владением объектом. Исходная переменная и контейнер становятся независимыми сильными владельцами одного экземпляра.
После image = nil объект всё ещё удерживается storage. Когда storage заменяется целым числом, прежнее содержимое освобождается; если это была последняя сильная ссылка, ARC запускает уничтожение объекта и затем deinit.
Важно отличать контейнер Any от слабой ссылки. Внутри Any нет автоматического ослабления владения: если требуется некритичное кэширование, нужно явно проектировать слабое хранилище, например отдельный объект-обёртку со свойством weak.
Если в Any помещается структура, контейнер удерживает саму структуру. При копировании структуры применяются правила копирования её свойств: сильные ссылочные свойства могут дополнительно удерживать содержащиеся объекты. Поэтому анализировать нужно весь граф ссылок, а не только внешний тип Any.
Оптимизатор может удалять ненужные временные значения раньше конца лексической области, но это не меняет семантику: пока контейнер логически содержит объект и нуждается в нём, его хранение является сильным.
В системе логирования события складывались в массив [Any], чтобы поддержать разные типы payload. После обработки массив очищался не сразу, а только после отправки пачки. В результате крупные объекты, помещённые в payload, удерживались дольше ожидаемого, хотя их исходные переменные уже исчезли.
Рассматривались варианты:
[Any] — просто и гибко, но владение неочевидно и время жизни может продлеваться;nil.Выбрали идентификаторы для крупных ресурсов, а Any оставили только для небольших значений-данных. Это сделало владение явным, устранило неожиданное удержание объектов и сохранило поддержку разнородных payload.
Нет. Копируется не сам экземпляр класса, а ссылка на него, помещённая в контейнер. После копирования два значения могут сильно удерживать один объект; изменение состояния объекта через одну ссылку будет видно через другую.
Контейнер удерживает структуру, а структура — объект через своё сильное свойство. Копирование такой структуры обычно не копирует экземпляр класса, а увеличивает число владельцев этого экземпляра. Поэтому уничтожение одного значения Any не обязано вызывать deinit вложенного объекта.
Нет, сам тип Any не предоставляет слабой семантики хранения. Для этого нужна отдельная ссылочная обёртка с weak-свойством либо специализированное хранилище; тогда Any будет сильно удерживать обёртку, но не объект, на который она ссылается.