В чём причина обязательного Optional-типа у weak-ссылки в Swift?
weak-ссылка не удерживает объект от уничтожения. Поэтому после деаллокирования объекта Swift автоматически обнуляет такую ссылку, а её тип должен уметь представлять состояние отсутствия — Optional.
Это отличает weak от сильной ссылки и от unowned: обращение к weak-ссылке после уничтожения объекта безопасно возвращает nil, тогда как обращение к недействительной unowned-ссылке приводит к аварийному завершению.
Ссылочные типы позволяют нескольким переменным указывать на один объект, но сильные ссылки увеличивают его счётчик удержания. Если объекты взаимно удерживают друг друга, возникает retain cycle: счётчик не достигает нуля, и память не освобождается.
Weak-ссылки предназначены для разрыва таких циклов без ручного управления памятью. Их ключевое свойство — отсутствие владения объектом и автоматическое обнуление после его уничтожения.
Представим объект-владелец и его делегат. Владелец обычно должен удерживать делегат, но делегат не должен удерживать владельца. Если обе ссылки будут сильными, объекты могут остаться в памяти даже после потери внешних ссылок.
Если бы weak-ссылка не могла стать nil, после уничтожения объекта она указывала бы на недействительную область памяти. Это создало бы опасный висячий указатель. Optional явно отражает реальное состояние weak-ссылки: объект либо доступен, либо уже отсутствует.
При чтении weak-ссылки Swift проверяет, жив ли объект. Пока объект существует, результатом является some(объект). После его уничтожения runtime устанавливает ссылку в nil, то есть в Optional.none.
Ссылка объявляется изменяемой, потому что runtime должен иметь возможность заменить её значение на nil. Кроме того, weak-ссылка применима только к экземплярам классов или к протоколам, ограниченным AnyObject: только ссылочные объекты имеют независимый жизненный цикл, за которым можно наблюдать.
Weak безопасен при исчезновении объекта, но чтение всё равно требует обработки Optional: например, через optional binding или optional chaining. В отличие от него, unowned не становится nil; он предполагает, что объект гарантированно переживёт ссылку, поэтому ошибка жизненного цикла превращается в runtime trap.
Компромисс weak — отсутствие гарантии доступности объекта между двумя моментами чтения. Если объект критически необходим для операции, его следует временно захватить сильной локальной ссылкой после проверки, чтобы он не исчез во время этой операции.
У ViewController есть делегат, который может быть уничтожен раньше контроллера. Сильная ссылка в контроллере создаёт риск retain cycle, если делегат также удерживает контроллер. unowned устраняет Optional, но опасен: он корректен только при доказанно связанном жизненном цикле и аварийно завершит программу при нарушении предположения.
Выбранное решение — weak var delegate: (any Delegate)?. Оно разрывает цикл, автоматически отражает исчезновение делегата через nil и позволяет контроллеру безопасно продолжить работу. Минусом является необходимость каждый раз учитывать отсутствие делегата, что является осознанной платой за безопасность.
Может ли weak-ссылка быть объявлена как let?
Нет, weak-ссылка должна быть изменяемой: runtime обнуляет её при уничтожении объекта. Поэтому объявление weak-свойства требует var, а не let. Неизменяемая сильная ссылка может быть let, поскольку она владеет объектом и не должна автоматически менять своё значение.
Гарантирует ли проверка weak-ссылки на nil, что объект останется жив во время всей последующей операции?
Нет, сама weak-ссылка владения не создаёт. После проверки объект может быть уничтожен другим кодом, если не существует другой сильной ссылки. Для надёжной операции нужно получить объект в локальную сильную переменную через optional binding; эта локальная переменная временно удержит объект.
Чем practically отличается weak от unowned?
weak допускает исчезновение объекта и автоматически становится nil, поэтому его тип Optional. unowned также не удерживает объект, но не отслеживает его отсутствие в форме Optional. Если объект уже уничтожен, обращение к unowned-ссылке вызывает аварийное завершение, поэтому её применяют только при гарантированно корректном порядке жизни объектов.