#xcode #debugging #instruments #dealloc #automatic-ref-counting
#xcode #отладка #инструменты #освобождение #автоматический подсчет ссылок
Вопрос:
Я потратил некоторое время на отладку странной проблемы с ARC и пользовательскими функциями освобождения.
- Я создаю подкласс
NSOperation
class - Я установил блок завершения для этой операции
- На операцию ссылается сильное свойство очень плоского объекта (нет методов, автоматических ивар, два сильных свойства), позволяет вызвать этот объект
DataRequest
- следуя всем рекомендациям, блок завершения использует только слабые ссылки на локальные объекты (включая саму операцию)
- ни компилятор, ни анализатор не создают никаких проблем
DataRequest
содержит ЕДИНСТВЕННУЮ ссылку на операцию, которую я создаю, и уничтожается в блоке завершения операции. Он ВСЕГДА уничтожается (dealloc
всегда выполняется)- Моя операция имеет обычай
dealloc
. В нем есть только один вызов NSLog.
… и проблема в том:
Если я запускаю это в отладчике, точка останова в освобождении никогда не будет достигнута, сообщение журнала никогда не появится. В первую очередь я думал, что операция протекает.
Если я запускаю это в инструментах, все в порядке, системная консоль печатает сообщение, а инструмент распределения сообщает, что операция освобождается от правильного снимка стека, включая пользовательский dealloc. Утечек не обнаружено.
Я на 100% уверен, что использую одни и те же настройки компилятора для отладки и профилирования.
Самое запутанное в конце: если я создаю пользовательскую версию [DataRequest dealloc]
и добавляю self.operation = nil;
к ней — все работает нормально даже из отладчика.
Есть ли у кого-нибудь какие-нибудь подсказки, какие параметры компоновщика компилятора можно попытаться увидеть какую-то разницу? может ли это быть ошибкой в инструментах Apple (все мы были в положении, обвиняя крупную рыбу в наших собственных ошибках, верно?)
… и да, я пробовал с GDB и LLDB. Результат был тот же — что может что-то указывать.
Я попытался создать минималистичный образец, но он просто сработал (действительно) 😉
Спасибо
Комментарии:
1. Я сделал очень простое наблюдение … если я запускаю приложение на симуляторе из XCode (GDB или LLDB), мои сообщения журнала
dealloc
не печатаются. Если я просто выхожу из отладчика и запускаю приложение прямо из симулятора — Console.app показывает все сообщения. Нет компиляции, нет промежуточных ссылок. Странно.2. … и еще один более простой результат… Если я запускаю приложение из XCode в сеансе отладки — освобождение не вызывается (журнал не печатается), если я запускаю приложение вручную в симуляторе, а затем подключаю отладчик… все, как и ожидалось.
Ответ №1:
У вас есть NSZombiesEnabled? У нас была такая же проблема, и мы «решили» ее, отключив NSZombies.
«Продукт» -> «Схема» -> «Редактировать схему» -> «Диагностика» -> Снимите флажок «Включить объекты зомби»
Я не уверен, почему dealloc не вызывается, когда включены NSZombies (я почти уверен, что он был вызван до ARC).
Комментарии:
1. Я должен протестировать — но да, у меня установлен NSZombiesEnabled. Это звучит вполне вероятно — и, по крайней мере, дает некоторое разумное объяснение отличному поведению.
2. Я могу подтвердить, что проблема вызвана NSZombiesEnabled. Большое спасибо!
3. Это может происходить повсеместно при использовании NSZombiesEnabled с ARC, а не только с
NSOperation
. Ключевым моментом при наблюдении странности освобождения с помощью ARC является отключение NSZombiesEnabled (который помечен как «Включенные объекты зомби» в схемах редактирования… > Вкладка Диагностики в Xcode 4.)4. Причина, по которой dealloc не вызывается, заключается в том, что объект никогда не освобождается. Это предотвращается и вместо этого превращается в «зомби»
5. @borrrden Я думаю, что его можно было бы освободить и просто заменить объектом-зомби по тому же адресу. AFAIK, вот как это работало до arc.
Ответ №2:
Сегодня я столкнулся с такой же проблемой, и мне потребовалось около 5 часов, чтобы обнаружить, что проблема была вызвана NSZombies, включенными в настройках моего проекта.
Я также согласен с тем, что перед ARC в этом случае вызывался dealloc .
После многих тестов выясняется, что освобождение не вызывается при использовании iOS 5.x (устройства или симулятора).
но он вызывается снова (с включенными зомби) в iOS 6.x (устройство или симулятор)
Я не знаю, вызвано ли это изменение ошибкой в ios5, которая была исправлена в ios6, или введенной и откатанной функцией.
Надеюсь, это поможет…
Ответ №3:
Сегодня я столкнулся с такой же проблемой, но моей проблемой был цикл сохранения, сгенерированный блоком.
Если вы используете блоки:
- Убедитесь, что SELF не отображается внутри блока.
- Если вам нужно использовать SELF внутри блока, используйте слабую ссылку.
- Убедитесь, что внутри блока нет макросов, которые могут ссылаться на self (например, NSAssert).