Что такое сильные и слабые ссылки в iOS?
Что проверяют
Понимаете ли вы, как работает подсчёт ссылок, и знаете ли разницу между двумя видами не удерживающих ссылок.
Как отвечать
Память освобождается автоматическим подсчётом ссылок: у объекта есть счётчик, и он живёт, пока счётчик больше нуля.
Сильная ссылка увеличивает счётчик и удерживает объект. Это поведение по умолчанию.
Слабая ссылка не увеличивает счётчик. Когда объект освобождается, ссылка автоматически становится пустой. Поэтому она обязательно изменяемая и необязательного типа.
Не владеющая ссылка тоже не увеличивает счётчик, но не обнуляется. Она не необязательная и обращение к ней после освобождения объекта роняет приложение. Взамен она чуть дешевле и не требует разворачивания.
Выбор между двумя последними: слабая по умолчанию, не владеющая только тогда, когда объект гарантированно живёт дольше ссылки на него.
Зачем это нужно: цикл сильных ссылок. Два объекта держат друг друга, счётчики никогда не доходят до нуля, память не освобождается. Два классических случая:
- делегат: родитель владеет дочерним объектом, а тот держит родителя как делегата. Свойство делегата объявляется слабым;
- замыкание, захватывающее объект, которое этот же объект и хранит. Лечится списком захвата со слабой ссылкой и последующей проверкой.
Важная оговорка: не всякое замыкание создаёт цикл. Не убегающие замыкания вроде преобразования коллекции выполняются сразу и ничего не удерживают. Разовый колбэк, который отработает и освободится, тоже обычно безопасен. Цикл появляется, когда замыкание хранится тем объектом, на который ссылается.
Обнаружение: инструмент поиска утечек и граф памяти в отладчике, показывающий, кто именно держит объект.
Где спотыкаются
Объявляют делегата сильной ссылкой.
Ставят слабый захват везде, включая не убегающие замыкания.
Берут не владеющую ссылку там, где объект может умереть раньше.
Забывают проверить слабую ссылку и молча пропускают выполнение.