Почему слабая ссылка в Swift должна быть optional?
Слабая ссылка должна быть optional, потому что она не владеет объектом: когда последняя сильная ссылка исчезает, ARC уничтожает объект и автоматически записывает nil во все его слабые ссылки. Неoptional-ссылка не смогла бы корректно представить состояние «объект уже уничтожен».
ARC автоматизирует подсчёт сильных ссылок, но не может сохранить объект только ради ссылки, которая не должна продлевать его жизнь. Для таких зависимостей нужен механизм, позволяющий наблюдать за объектом без владения им.
В ручном управлении памятью аналогичная ссылка могла стать висячей: адрес оставался доступным после освобождения объекта. weak решает эту проблему иначе: среда выполнения отслеживает объект и обнуляет слабую ссылку перед или в момент его уничтожения.
Представим делегат, который должен существовать независимо от владельца. Если хранить его сильной ссылкой, владелец продлит жизнь делегата, а в некоторых схемах это создаст цикл ссылок.
Если же делегат будет уничтожен раньше владельца, владелец должен получить безопасное состояние «делегата больше нет». Именно поэтому тип слабой ссылки допускает nil; попытка представить такую ссылку как гарантированно существующий объект была бы некорректной.
weak не увеличивает счётчик сильных ссылок объекта. Когда объект ещё жив, чтение слабой ссылки возвращает его; после уничтожения объекта чтение возвращает nil.
Слабая ссылка поэтому объявляется как optional-ссылка, например Delegate?. Это не просто синтаксическое ограничение: optional отражает реальное изменение состояния ссылки во времени — от ссылки на объект до отсутствия объекта.
Ограничение AnyObject нужно потому, что weak применяется к ссылочным типам. Значения структур и перечислений не имеют независимого объектного времени жизни, которое можно было бы отслеживать таким способом.
Слабое свойство также должно быть изменяемым (var): ARC может автоматически заменить его значение на nil. Объявление let не подходит, поскольку оно запрещает такое изменение.
weak следует выбирать, когда отсутствие объекта является нормальным состоянием и владелец не должен продлевать его жизнь. Если объект обязан существовать дольше ссылки, применяют unowned, но обращение к такой ссылке после уничтожения объекта приводит к аварийному завершению, а не к nil.
В экранном контроллере хранится делегат сетевого сервиса. Сервис может завершить работу и быть освобождён раньше контроллера, поэтому сильная ссылка со стороны контроллера была бы неверной: она не отражает владение и может удерживать сервис дольше необходимого.
Вариант с unowned уменьшает накладные расходы проверки на nil, но требует строгой гарантии, что сервис переживёт контроллер. При нарушении этой гарантии приложение аварийно завершится.
Выбранный вариант — weak var delegate: (any Delegate)?. После освобождения сервиса свойство станет nil, а вызов через optional chaining просто не выполнится. Это безопаснее и соответствует неопределённому времени жизни делегата.
let?Нет. Слабая ссылка должна быть var, поскольку ARC автоматически записывает в неё nil, когда объект уничтожается. Это изменение происходит без явного присваивания со стороны программы, поэтому неизменяемая ссылка здесь невозможна.
weak нельзя применить к структуре?weak отслеживает время жизни ссылочного объекта и не владеет им. Структура является значением: при передаче или копировании создаётся новое значение, а не независимый объект с общим счётчиком ссылок. Поэтому слабые ссылки применимы к классам и другим ссылочным типам, но не к обычным структурам и перечислениям.
nil в слабом свойстве с точки зрения владения?nil означает, что доступного объекта больше нет или ссылка ещё не была установлена. Это не временное уменьшение числа сильных ссылок: слабая ссылка вообще не владеет объектом. Установка nil в слабое свойство не уничтожает объект, а уничтожение объекта ARC автоматически отражает в слабом свойстве его недоступность.