После освобождения объекта, на который указывает weak-ссылка, что произойдёт с этой ссылкой и почему?
weak-ссылка не удерживает объект от освобождения. Когда исчезает последняя сильная ссылка и объект уничтожается, Swift автоматически устанавливает weak-ссылку в nil; поэтому она всегда имеет опциональный тип.
ARC автоматизировал управление временем жизни экземпляров классов, но не устранил проблему циклических ссылок. Для связей, в которых один объект должен наблюдать или использовать другой, не продлевая его жизнь, был нужен безопасный тип не владеющей ссылки.
weak решает эту задачу за счёт обнуляемой ссылки: она не увеличивает счётчик сильных ссылок и автоматически становится nil после уничтожения объекта.
Рассмотрим делегат, кэш или владельца временного ресурса. Если такая связь будет сильной, объект может удерживаться дольше ожидаемого или образовать цикл владения, из-за чего ARC не сможет его освободить.
Если вместо weak использовать обычную сильную ссылку, возможна утечка памяти. Если без проверки обратиться к weak-ссылке после уничтожения объекта, логика приложения может ошибочно предполагать, что зависимость всё ещё доступна.
Объект живёт, пока на него существует хотя бы одна сильная ссылка. weak-ссылка не участвует в подсчёте владения: она лишь отслеживает объект. Когда объект уничтожается, среда выполнения обнуляет все weak-ссылки на него.
Поэтому объявление weak-ссылки требует опциональности. Перед использованием нужно учитывать состояние nil, например через optional binding или optional chaining.
Ограничение AnyObject означает, что такой делегат может быть только экземпляром класса: weak-ссылки применимы к ссылочной семантике, а не к структурам или перечислениям.
weak отличается от unowned. unowned также не удерживает объект, но не обнуляется и предполагает, что объект гарантированно будет жить дольше ссылки. Нарушение этого предположения приводит к аварийному завершению при обращении, тогда как weak даёт безопасный nil, но требует обработки отсутствия объекта.
Экран владеет сервисом загрузки, а сервис уведомляет экран через делегат. Сильная ссылка сервиса на экран создала бы цикл: экран удерживает сервис, сервис удерживает экран, и оба объекта не освобождаются.
Возможны два решения. unowned не требует проверки nil и подходит, если жизненные циклы строго связаны, но ошибка в этом предположении приведёт к аварийному завершению. weak безопаснее для делегата: после закрытия экрана сервис получает nil и прекращает уведомления, однако код должен корректно обработать отсутствие делегата.
Для обычного делегатного отношения выбирают weak. Это предотвращает цикл владения и не требует доказывать, что делегат гарантированно переживёт источник уведомлений.
1. Почему weak-ссылка обязательно опциональна?
Потому что после уничтожения объекта она должна иметь представимое состояние отсутствия — nil. Неопциональная ссылка не смогла бы корректно выразить тот факт, что объект больше недоступен.
2. Может ли weak-ссылка сохранить объект от уничтожения на время чтения?
Нет. Чтение weak-ссылки не превращает её в владельца. Если объект может быть освобождён конкурентно, локальную сильную ссылку нужно получить в безопасном для конкретной архитектуры месте и затем работать уже с ней; сама weak-ссылка гарантий владения не даёт.
3. Когда предпочтительнее unowned, а не weak?
unowned уместен, когда жизненный цикл ссылки строго подчинён жизненному циклу объекта, например зависимый объект не может существовать без владельца. Он избавляет от optional-проверок, но цена — аварийное завершение при нарушении инварианта. Если жизненные циклы могут расходиться или это сложно гарантировать, предпочтительнее weak.