Зачем Swift требует объявлять weak-ссылку переменной, а не константой?
weak-ссылка должна быть переменной, потому что ARC может автоматически заменить её значение на nil после уничтожения объекта. Константная ссылка не допускает такого изменения, поэтому не может поддерживать семантику обнуляемой слабой ссылки.
Слабые ссылки нужны для наблюдения за объектом без увеличения его счётчика сильных ссылок. Изначально такой подход решал проблему циклов владения, но обычная невладеющая ссылка могла стать висячей после уничтожения объекта.
Zeroing weak references устраняют этот риск: среда выполнения отслеживает слабые ссылки и обнуляет их, когда объект перестаёт существовать. Поэтому слабая ссылка должна храниться в изменяемом месте.
Если бы weak-ссылка была константой, её значение нельзя было бы изменить после деаллокации объекта. Обращение к ней могло бы использовать адрес уже уничтоженного экземпляра, что привело бы к неопределённому поведению или аварийному завершению.
Важно отличать неизменность самого объекта от неизменности ссылки. Даже если объект после создания не меняется, слабая ссылка на него всё равно может быть автоматически заменена на nil.
При создании weak-ссылки она не становится владельцем объекта: счётчик сильных ссылок не увеличивается. Если все сильные ссылки исчезают, объект освобождается, а связанные с ним weak-хранилища обнуляются.
Именно поэтому weak-ссылка обычно объявляется как var и имеет optional-тип. var позволяет runtime записать nil, а optional допускает отсутствие объекта до его уничтожения или после него.
После присваивания nil переменной session экземпляр больше не имеет сильных владельцев. ARC освобождает его, а controller.session автоматически становится nil. Объявление weak-ссылки через let невозможно, поскольку let запрещает изменение самого хранилища ссылки.
Это ограничение относится именно к weak. Сильная ссылка может быть let, если требуется неизменная привязка к объекту, потому что сильное владение не предполагает автоматического обнуления ссылки при деаллокации.
Контроллер хранит ссылку на объект сессии, но не должен продлевать его жизнь. Вариант с сильным свойством прост, однако сессия может оставаться в памяти дольше необходимого и образовать цикл владения через другие компоненты.
Вариант с unowned не увеличивает время жизни, но обращение после уничтожения сессии завершится ошибкой. Вариант с weak var безопаснее: после деаллокации сессии свойство станет nil, и контроллер сможет обработать отсутствие объекта.
Выбранное решение — weak var session: Session?, если сессия может исчезнуть раньше контроллера. Результат: нет дополнительного владения, нет висячей ссылки и есть возможность явно обработать nil.
Вопрос: может ли weak-ссылка оставаться ненулевой после того, как объект потерял последнюю сильную ссылку?
Нет, для корректной weak-ссылки после уничтожения объекта она должна быть обнулена. Небольшие различия в моменте фактической деаллокации не меняют гарантии: доступ к weak-ссылке после завершения жизни объекта даёт nil, а не ссылку на освобождённую память.
Вопрос: почему изменение weak-ссылки не продлевает жизнь объекта?
Запись объекта в weak-свойство регистрирует ссылку в специальном weak-хранилище, но не создаёт сильного владения. Поэтому наличие ненулевого значения weak-ссылки само по себе не препятствует ARC уничтожить объект, когда исчезнет последняя сильная ссылка.
Вопрос: почему для weak-ссылки недостаточно сделать ссылку переменной, но необязательно явно присваивать ей nil?
Обнуление выполняет runtime автоматически в рамках механизма zeroing weak references. Разработчик не обязан отслеживать момент деаллокации объекта и вручную очищать все слабые ссылки. var требуется не для ручного управления памятью, а чтобы runtime мог безопасно изменить значение хранилища.