Выпуск Objective-C объекта-зомби после модификации раскадровки
У меня есть некоторые проблемы в iOS-приложении. После расследования я обнаружил, что эта проблема - какой-то висячий указатель. Чтобы выяснить, откуда он взялся, я начал профилировать код на симуляторе (iOS 6.1), используя шаблон трассировки "Зомби".
Тестовый сценарий довольно прост: выберите какой-либо элемент на столе, затем перейдите к следующему контроллеру, вызвав правильное колебание по его имени, затем нажмите кнопку "Назад". Раздавление появляется, когда анимация "назад" закончена.
Вот профилировщик табличной формы с данными для освобожденного объекта зомби (я удалил неинтересные столбцы, такие как: #; Category - всегда равен CALayer; отметка времени):
Event Type RefCt Size Responsible Library Responsible Caller
Malloc 1 48 UIKit -[UIView _createLayerWithFrame:]
Retain 3 0 QuartzCore CA::Layer::insert_sublayer(CA::Transaction*, CALayer*, unsigned long)
Release 2 0 UIKit -[UIView(Internal) _addSubview:positioned:relativeTo:]
Retain 3 0 QuartzCore -[CALayerArray mutableCopyWithZone:]
Release 2 0 UIKit -[UIView(Hierarchy) bringSubviewToFront:]
Retain 3 0 QuartzCore -[CALayerArray copyWithZone:]
Release 2 0 UIKit -[UIView(Hierarchy) _makeSubtreePerformSelector:withObject:withObject:copySublayers:]
Retain 3 0 QuartzCore -[CALayerArray copyWithZone:]
Release 2 0 UIKit -[UIView(Internal) _didMoveFromWindow:toWindow:]
Retain 2 0 QuartzCore -[CALayerArray copyWithZone:]
Release 1 0 UIKit -[UIView(Hierarchy) _makeSubtreePerformSelector:withObject:withObject:copySublayers:]
Retain 3 0 QuartzCore -[CALayerArray copyWithZone:]
Release 2 0 UIKit -[UIView(Internal) _didMoveFromWindow:toWindow:]
Retain 3 0 QuartzCore -[CALayerArray copyWithZone:]
Release 2 0 UIKit -[UIView dealloc]
Release 1 0 UIKit -[UIView dealloc]
Zombie -1 0 QuartzCore CA::release_objects(X::List<void const*>*)
Теперь эта таблица нигде не указывает на мой код, все записи относятся к системным библиотекам: UIKit или QuartzCore. Поэтому я не могу показать свой код, так как понятия не имею, какая часть неправильная, а ее много.
Когда я пытаюсь просмотреть историю изменений, единственными существенными изменениями в первом коммите с этой проблемой являются изменения, сделанные в раскадровке. Это странно, поскольку изменения в раскадровке не должны иметь таких проблем. Я не могу сказать, что именно было изменено (раскадровка XML очень трудно читать).
Любое предложение, как я могу найти / исправить эту проблему? Или может у кого-то была похожая проблема?
2 ответа
Я очень подозрительно отношусь к:
Release 2 0 UIKit -[UIView dealloc]
Release 1 0 UIKit -[UIView dealloc]
Каковы стеки вызовов для этих вызовов?
В прошлом у меня были проблемы, вызванные неправильным освобождением свойств в -dealloc
, Просто чтобы быть уверенным, я опечатываю указатели после выпуска их в -dealloc
,
[_prop release]; _prop = nil;
Наконец я нашел проблему.
Проблема была вызвана неправильным слиянием и для некоторых IBOutlet
имущество release
метод был вызван дважды при освобождении контроллеров. Эти вызовы были разделены другими вызовами выпуска для других свойств, поэтому было легко пропустить. Проблема в рабочем коде, но не появилась раньше, так как он был в контроллере корневого представления (так что он жил столько же, сколько приложение). (Я унаследовал такой "замечательный" код)
Теперь у меня есть новая спецификация пользовательского интерфейса и порядок изменения контроллеров, и проблемный контроллер больше не является первым в стеке контроллеров представления, поэтому он освобождается и ошибка начинает проявляться самостоятельно.
Я потратил два рабочих дня, чтобы найти это:).
Спасибо вам: "Джеффри Томас" и "Бернд Рабе", ваши отзывы позволили мне найти проблему.
Забавно, что инструмент XCode: "Продукт / Анализ" не обнаружил этого. Определенно так и должно быть.
Также Profiler при отслеживании зомби должен жаловаться на объект, который является корнем проблемы, теперь он жалуется на потомка проблемного объекта. Просто исключение зомби должно быть повышено до того, как Deloloc был вызван, а не после.