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