При передаче экземпляра Swift-класса в Objective-C API кто гарантирует его жизнь до завершения вызова?
Жизнь экземпляра до завершения вызова гарантирует сама семантика передачи аргумента: вызываемый Objective-C метод получает действительный объект на всё время выполнения вызова. ARC может использовать временное заимствование вместо фактического retain, если это безопасно, поэтому наличие видимого увеличения счётчика ссылок не является обязательным.
После возврата из метода объект может быть уничтожен, если не осталось других сильных владельцев. Если Objective-C API сохраняет объект для последующего использования, оно обязано сделать собственное владение: например, сохранить сильную ссылку или скопировать объект согласно контракту API.
ARC появился как автоматизация ручного управления retain/release, характерного для Objective-C. Исходная проблема заключалась в необходимости вручную балансировать владение объектами и одновременно гарантировать, что объект не будет освобождён во время вызова.
При взаимодействии Swift и Objective-C компилятор анализирует границы вызовов и вставляет необходимые операции управления временем жизни. Оптимизации могут заменять реальные retain/release временными гарантиями жизни, не меняя наблюдаемую корректность программы.
Рассмотрим метод, который получает объект, но не сохраняет его, а только использует внутри вызова. Если вызывающая сторона обнулит свою последнюю сильную ссылку во время подготовки или выполнения вызова, объект всё равно не должен исчезнуть до завершения обращения к нему.
Иная ситуация возникает, если Objective-C API сохраняет указатель или объект для асинхронной работы, но не увеличивает владение. Тогда после возврата метода объект может быть уничтожен, а сохранённая ссылка станет недействительной. Ошибка находится уже на стороне контракта API, а не в обычной работе ARC.
На границе вызова аргумент должен оставаться валидным в течение всего времени, когда вызываемый код может им пользоваться. Это не означает, что ARC обязан выполнить отдельный сильный retain именно перед вызовом: компилятор вправе применить borrowed-передачу, если доказано, что нужная гарантия уже обеспечена другим владением.
Нужно различать два случая:
ARC управляет обычными сильными ссылками Swift и корректными Objective-C соглашениями о владении, но не может исправить API, которое хранит указатель без владения. Особенно опасны такие указатели при асинхронных callback-ах, C-структурах и ручном использовании Unsafe.
Следовательно, по трассировке retain/release нельзя делать вывод, что объект обязательно получил отдельную сильную ссылку на время каждого вызова. Надёжный вывод определяется семантикой владения и действительностью объекта в рамках вызова, а не конкретной последовательностью оптимизированных инструкций.
Контроллер передаётся в Objective-C-компонент для регистрации обработчика. Компонент использует контроллер только во время регистрации — это безопасный сценарий: вызов гарантирует валидность аргумента, а после возврата контроллер может быть уничтожен.
Если компонент сохраняет обработчик для будущего события, возможны варианты:
Практически выбирают слабую ссылку, если событие не должно продлевать жизнь контроллера, и обеспечивают явное снятие регистрации. Если компонент обязан гарантировать доставку события, сильное владение допустимо, но граф владения нужно разорвать при завершении работы.
Нет. Он обязан обеспечить корректность использования объекта во время вызова, но конкретный retain может быть устранён оптимизатором. Если объект требуется после возврата, метод должен явно сохранить его во владении.
Нет, сама передача не создаёт долгосрочного владения. После завершения вызова объект может быть уничтожен, если у него нет других сильных ссылок. Продление жизни возникает только при сохранении объекта API с корректной семантикой владения.
После исчезновения последней сильной ссылки объект может быть уничтожен, и указатель станет недействительным. Последующее обращение приведёт к неопределённому поведению или аварийному завершению; ARC не отслеживает произвольные необладающие указатели. Такой API нужно адаптировать: передавать объект с явным владением, использовать безопасный callback-контракт или гарантировать, что владелец живёт дольше сохранённого указателя.