Влияет ли ссылка unowned на время жизни объекта?

Влияет ли ссылка unowned на время жизни объекта?

Проходите собеседования с ИИ помощником Hintsage

Краткий ответ

Нет. Ссылка unowned не увеличивает счётчик сильных ссылок, поэтому не продлевает жизнь объекта: экземпляр может быть уничтожен, когда исчезнет последняя сильная ссылка. После этого обращение к обычной unowned-ссылке приводит к runtime-ошибке.

Исторический контекст

ARC автоматизировал управление памятью на основе подсчёта ссылок, избавив разработчика от ручного вызова операций удержания и освобождения объектов. Однако циклы владения невозможно устранить одним только подсчётом ссылок, поэтому в Swift предусмотрены не владеющие ссылки — weak и unowned.

Они решают разные варианты одной исходной проблемы: объект должен быть доступен по ссылке, но эта ссылка не должна сама удерживать его в памяти.

Постановка проблемы

Если сохранить связь между объектами как сильную, она увеличит количество владельцев и может сформировать retain cycle. Объекты останутся недостижимыми для остального приложения, но ARC не сможет освободить их, поскольку их счётчики ссылок не равны нулю.

unowned устраняет владение, но вводит требование к корректности программы: объект, на который ссылаются, обязан существовать в момент каждого обращения. Если это условие нарушено, безопасная unowned-ссылка не превращается в nil, а аварийно завершает выполнение.

Подробное решение

ARC учитывает только ссылки, которые владеют экземпляром. Сильная ссылка увеличивает число владельцев, а уничтожение последней сильной ссылки делает объект доступным для деинициализации. Ссылка unowned в этот подсчёт не входит.

final class Session { var delegate: Handler? deinit { print("session deinit") } } protocol Handler: AnyObject {} var session: Session? = Session() var handler: Handler? = nil session = nil

В этом примере session будет освобождён после обнуления последней сильной ссылки независимо от наличия unowned-ссылок на него. Само хранилище unowned сохраняется отдельно и не удерживает экземпляр.

Обычная unowned-ссылка предполагает гарантированное время жизни объекта. Если объект уже уничтожен, обращение к ссылке вызывает ошибку времени выполнения. Вариант unowned(unsafe) не выполняет такую проверку и может привести к неопределённому поведению, поэтому его применение требует ещё более строгого контроля.

В отличие от weak, unowned не является optional и не обнуляется при уничтожении объекта. Выбирайте unowned только при доказуемой гарантии: владелец ссылки переживает объект, либо ссылка используется исключительно пока объект гарантированно жив. Если объект может исчезнуть раньше, нужна weak-ссылка и проверка на nil.

Ситуация из практики

В компоненте приложения вспомогательный объект хранит ссылку на координатор. Координатор создаёт и владеет вспомогательным объектом, а вспомогательный объект обращается к координатору для отправки результата. Сильная обратная ссылка сформировала бы цикл и не позволила бы координатору освободиться.

Рассматривались два решения. weak безопаснее: ссылка станет nil, если координатор исчезнет, но чтение требует optional-логики и связано с дополнительной runtime-обработкой. unowned не добавляет владения и удобнее для обязательной обратной связи, однако обращение после уничтожения координатора аварийно завершит приложение.

Если архитектура гарантирует, что вспомогательный объект не может пережить координатор, выбирается unowned. Если объект может быть передан в другое место, сохранён отдельно или использован асинхронно после уничтожения координатора, правильнее выбрать weak. Результат такого выбора — отсутствие цикла без риска обращения к уже уничтоженному объекту.

Что кандидаты часто упускают

  1. Может ли объект быть уничтожен, если на него всё ещё указывает unowned-ссылка?

    Да. unowned не является владельцем и не препятствует уменьшению числа сильных ссылок до нуля. Наличие такой ссылки не учитывается ARC при принятии решения об уничтожении экземпляра.

  2. Что произойдёт при обращении к обычной unowned-ссылке после уничтожения объекта?

    Программа завершится с ошибкой времени выполнения. В отличие от weak, ссылка не станет nil, поэтому optional-проверка не защищает от этой ошибки. Это делает unowned подходящей только при гарантированно корректном порядке жизни объектов.

  3. Почему в сомнительной ситуации лучше выбрать weak, даже если сейчас время жизни объектов кажется очевидным?

    Гарантия может перестать выполняться после добавления асинхронной операции, кэширования, передачи объекта в другой компонент или изменения порядка освобождения. weak обнуляется автоматически и позволяет штатно обработать исчезновение объекта, тогда как unowned превращает нарушение предположения в аварийное завершение.