Можно ли вывести объект из управления ARC в Swift
Что проверяют
Знаете ли вы, где заканчивается ARC и начинается ручное управление памятью. Обычно вопрос вырастает из работы с C API и Core Foundation, следом спрашивают про Unmanaged и чем грозит ошибка в балансе retain и release.
Как отвечать
ARC управляет ссылочными типами: экземплярами классов, акторов, замыканиями. Полностью отключить его для объекта нельзя, но подсчёт ссылок можно взять в свои руки:
Unmanaged<T>: обёртка для передачи объекта туда, где ARC не работает.Unmanaged.passRetained(obj)добавляет +1 и гарантирует, что объект доживёт до конца,passUnretained(obj)передаёт без владения. ВызовtoOpaque()даёт сырой указатель, который уходит в C-колбэк какvoid *context;- обратное преобразование:
Unmanaged<T>.fromOpaque(ptr)и затемtakeRetainedValue(), если нужно забрать владение и сбалансировать +1, илиtakeUnretainedValue(), если владение не передавалось. Есть и ручныеretain()иrelease(); - Core Foundation: аннотированные функции ARC обслуживает сам, а неаннотированные возвращают
Unmanaged<CFString>и подобные. Тогда действует правило Create и Copy: если в имени функции естьCreateилиCopy, результатом владеете вы и зовётеtakeRetainedValue(); - сырая память:
UnsafeMutablePointer<T>.allocate(capacity:),initialize(to:),deinitialize(count:)иdeallocate(). Сам буфер ARC не освобождает, это ваша задача; unowned(unsafe): ссылка без удержания и без проверки. По сути указатель, который после освобождения объекта становится висячим.
weak и обычный unowned ничего из ARC не выводят: это те же механизмы ARC, просто без удержания объекта.
Где спотыкаются
Называют weak способом вывести объект из-под ARC. Слабая ссылка работает внутри ARC и обнуляется автоматически, это противоположность ручному управлению.
Путают takeRetainedValue() и takeUnretainedValue(). Лишний release даёт падение с EXC_BAD_ACCESS, недостающий оставляет утечку, которую потом видно в Instruments.
Передают в асинхронный C-колбэк passUnretained. Пока колбэк ждёт вызова, последняя сильная ссылка исчезает, объект освобождается, и колбэк работает с висячим указателем.