Где хранятся strong и weak ссылки
Что проверяют
Понимаете ли вы, как ARC устроен внутри, а не только правило «делегат делайте weak». Следом обычно спрашивают, чем weak отличается от unowned и почему weak-ссылка сама становится nil.
Как отвечать
Сначала разделите два вопроса: где лежит сама ссылка и где лежат счётчики.
- сама ссылка: это указатель, и лежит он там же, где переменная. Локальная переменная на стеке, свойство класса в куче внутри объекта-владельца, захваченная переменная в контексте замыкания, тоже в куче;
- объект класса: всегда в куче. В его заголовке указатель на метаданные и поле счётчика ссылок;
- strong и unowned: счётчики хранятся прямо в этом поле заголовка, без отдельной аллокации.
С weak в Swift интереснее. Когда на объект впервые создаётся weak-ссылка, рантайм выделяет side table: отдельную структуру в куче со счётчиками strong, unowned и weak. Поле в заголовке объекта начинает указывать на неё, а weak-переменная хранит указатель на side table, а не на объект. Когда strong-счётчик падает до нуля, выполняется deinit, и память объекта освобождается (если нет unowned-ссылок), а side table живёт, пока на неё смотрят weak-ссылки. При обращении weak-ссылка видит, что объект мёртв, и возвращает nil.
Хорошо добавить сравнение с Objective-C: там weak-указатели регистрируются в глобальной таблице рантайма по адресу объекта, и при dealloc рантайм обнуляет их все.
Практические следствия: weak всегда var и опционал, первое создание weak-ссылки стоит аллокации, а unowned дешевле, но обращение через него к освобождённому объекту роняет приложение.
Где спотыкаются
Отвечают, что strong-ссылки в куче, а weak на стеке. Место хранения указателя зависит от переменной, а не от вида ссылки.
Путают структуры и классы: у значения типа struct нет счётчика ссылок, ARC работает с экземплярами классов и контекстами замыканий.
Говорят, что ARC при освобождении обходит и зануляет все weak-ссылки. Это модель Objective-C, в Swift обнуление ленивое, через side table.