Какую гарантию даёт withExtendedLifetime, которой обычная локальная ссылка ARC не обязана обеспечивать?
withExtendedLifetime гарантирует, что переданное значение будет жить как минимум до завершения синхронного выполнения указанного замыкания. Обычная сильная локальная ссылка не обязана удерживать объект до конца лексической области: ARC может освободить его после последнего существенного использования.
ARC автоматизировал управление сильными ссылками, но сохранил возможность оптимизировать места добавления и удаления временных удержаний. Поэтому область видимости переменной и гарантированный срок жизни объекта — не одно и то же.
Проблема особенно заметна при взаимодействии с небезопасными указателями, системными API и внешним кодом, который не выражает владение объектом через обычную ссылку. Для таких границ нужен явный способ сообщить компилятору, до какого момента значение должно оставаться живым.
Если объект используется только для получения указателя или другого временного представления, компилятор может считать, что сильная ссылка больше не нужна, сразу после последнего обычного обращения к объекту. Формальное достижение конца функции или блока само по себе не гарантирует, что объект будет жить до этой точки.
Преждевременное уничтожение может привести к обращению к недействительному указателю, нарушению контракта внешнего API или выполнению deinit раньше ожидаемого момента. При этом withExtendedLifetime не превращает ссылку в бессрочное владение и не управляет временем жизни асинхронной операции.
withExtendedLifetime принимает значение и синхронное замыкание. Пока замыкание выполняется, переданное значение считается живым; после выхода из замыкания эта дополнительная гарантия заканчивается.
В примере объект гарантированно жив во время выполнения тела замыкания. Без этой границы ARC мог бы завершить его время жизни раньше конца process, если после последнего реального использования переменная больше не нужна.
Гарантия относится к переданному значению, а не ко всем объектам, которые оно косвенно использует. Она также не переносится на escaping-замыкание, Task или другую асинхронную работу: тело withExtendedLifetime должно завершиться синхронно.
Функция не гарантирует немедленный вызов deinit после выхода из тела. Она лишь запрещает завершить жизнь значения раньше установленной границы; дополнительные сильные ссылки, внутренние удержания и особенности аллокатора могут сохранить объект дольше.
Модуль получает экземпляр ресурса Swift, временно извлекает из него адрес буфера и передаёт этот адрес синхронной функции на C-уровне. Вариант с обычной локальной ссылкой может оказаться недостаточно выразительным: её последнее использование способно завершиться до того, как внешняя функция закончит работу с адресом.
Можно искусственно добавить обращение к объекту после вызова внешней функции. Это плохо читается, зависит от оптимизаций и выглядит как случайный обход поведения ARC. Можно также удерживать объект отдельной сильной переменной дольше всей функции, но это расширяет время жизни без точной границы.
Выбранный вариант — withExtendedLifetime вокруг всей синхронной операции. Он явно описывает контракт, не создаёт долгожившее владение и облегчает ревью кода. Если операция асинхронная, вместо него нужен настоящий механизм владения, передача объекта в асинхронную задачу или иной контракт API.
Продлевает ли withExtendedLifetime жизнь объекта до конца функции?
Нет. Гарантия действует только до завершения переданного синхронного замыкания. Если объект нужно удерживать дольше, его следует передать в соответствующую долгоживущую операцию или сохранить сильной ссылкой в объекте-владельце.
Можно ли использовать withExtendedLifetime для безопасного доступа из фонового потока?
Сам по себе — нет. Он задаёт границу времени жизни, но не обеспечивает потокобезопасность, синхронизацию и отсутствие одновременной мутации. Доступ к объекту и его данным всё равно должен соответствовать требованиям конкретного API и модели конкурентности.
Что произойдёт, если передать в withExtendedLifetime слабую ссылку?
Слабая ссылка не становится сильным владельцем автоматически на весь ожидаемый период. Нужно сначала получить сильное значение из слабой ссылки и передать именно его в withExtendedLifetime; иначе объект может исчезнуть до формирования нужного значения или до начала операции. Даже после этого гарантия действует только синхронно внутри тела замыкания.