Как я могу безопасно переключаться между методами ARC и MRC без необходимости сохранять / освобождать вызовы?
У меня есть класс ARC со следующим кодом:
[object doStuffWithObject:otherObject];
object
"s -doStuffWithObject:
Метод скомпилирован с ARC, и это:
- (void)doStuffWithObject:(id)otherObject
{
DoStuffHelper(object, otherObject);
}
DoStuffHelper
, функция C, не скомпилирована с ARC (по соображениям производительности). В DoStuffHelper
мне нужно позвонить -retain
в начале для object
а также otherObject
а также -release
для них в конце?
4 ответа
См. Раздел " Избегайте выделения выделенных объектов, которые вы используете", в разделе " Расширенное управление памятью: практическое управление памятью", в котором они отмечают, что "полученные объекты обычно должны оставаться действительными во всей области вызывающего метода", т.е. retain
а также release
не являются необходимыми, за исключением следующего предостережения:
Есть редкие исключения из этого правила, в первую очередь попадающие в одну из двух категорий.
Когда объект удаляется из одного из базовых классов коллекции.
heisenObject = [array objectAtIndex:n]; [array removeObjectAtIndex:n]; // heisenObject could now be invalid.
Когда объект удаляется из одного из базовых классов коллекции, ему отправляется
release
(скорее, чемautorelease
) сообщение. Если коллекция была единственным владельцем удаленного объекта, удаленный объект (heisenObject
в примере) немедленно освобождается.Когда "родительский объект" освобожден.
id parent = <#create a parent object#>; // ... heisenObject = [parent child] ; [parent release]; // Or, for example: self.parent = nil; // heisenObject could now be invalid.
В некоторых ситуациях вы извлекаете объект из другого объекта, а затем прямо или косвенно освобождаете родительский объект. Если освобождение родителя вызывает его освобождение, и родитель был единственным владельцем дочернего элемента, то дочерний элемент (
heisenObject
в примере) будет освобожден в то же время (при условии, что он отправил релиз, а неautorelease
сообщение в родительскомdealloc
метод).Чтобы защитить от этих ситуаций, вы сохраняете
heisenObject
после получения, и вы отпускаете его, когда закончите с ним. Например:heisenObject = [[array objectAtIndex:n] retain]; [array removeObjectAtIndex:n]; // Use heisenObject... [heisenObject release];
Я был бы удивлен, если бы ваша вспомогательная функция попала в одну из этих категорий. Вы, вероятно, будете в порядке без retain
а также release
Но я упоминаю об этом только ради полного раскрытия.
Очевидно, вам может понадобиться свой собственный retain
а также release
если ваши функции нуждаются в этом по другим причинам (например, если задача асинхронная или если вы делаете что-то необычное, когда объект должен пережить область действия вызывающего метода), но я подозреваю, что вы упомянули бы это, если бы выполняли одну из этих вещи.
Кроме того, если бы ваша служебная функция создавала и возвращала объект, то это было бы другое дело (например, вы обычно autorelease
объекты, которые вы возвращали).
Нет. DoStuffHelper не является объектом, который утверждает право собственности на object
или же otherObject
, Это просто служебная функция, которая работает с ними напрямую. По сути, это часть вашего класса ARC, который уже выполняет полное управление памятью для этих объектов.
В подавляющем большинстве случаев вы не найдете ARC медленнее, чем традиционные сохранения / выпуска. Вы использовали инструменты, чтобы проверить проблему?
Сказав это, вам не нужно сохранять / освобождать объект в DoStuffHelper(), потому что retainCount уже будет>= 1 при входе. Если объекты хранятся в статических или глобальных объектах, вам необходимо их сохранить.
DoStuffHelper, функция C, не скомпилирована с ARC (по соображениям производительности).
Есть ли у вас измерения производительности, которые показывают, что ARC медленнее?
В общем случае исполняемые файлы ARC, сгенерированные с включенным оптимизатором, будут быстрее, чем тот же код с отключенным ARC (и оптимизирован компилятором).
Это связано с тем, что компилятор (и среда выполнения) могут рассуждать о ссылках на возможность избежать вызовов retain
а также release
(и, что еще хуже, autorelease
) при этом указанные вызовы будут обязательными в правильном коде MRR.
Если у вас есть шаблон кода, где это не так, я бы хотел зафиксировать этот шаблон и сообщить об ошибке.
(Это, по общему признанию, мета-ответ. Он ставит под сомнение необходимость даже в таком интерфейсе ARC-MRR. Поддерживая кодовые базы, которые являются частично ARC и частично MRR, такие смеси изобилуют хрупкостью.)