Ловим зомби объекты в iOS (XCode) или как решать message sent to deallocated instance

История начинается с того, что жил был один наследник UITextView. Это был не простой наследник, а наследник, использующийся в чате. Этакий инпут для сообщений чата. Жил он себе не тужил, как в один прекрасный момент начал доводить своими падениями.

Этот монстр выдавал сухую ошибку exc_bad_access в консоли. Больше ничего не говорил. Я обнаружил последовательность в которой происходит этот крэш. Обнаружилось, что ошибка возникает в момент deinit этого класса.

deinit

Очень странное поведение. Тем более правильное и логичное. И тем не менее возникает EXC_BAD_ACCESS. Эта ошибка может возникать в 3-х случаях:

  1. Объект не инициализирован
  2. Объект уже уничтожен
  3. Все остальное

В моем случае можно однозначно утверждать, что объект был инициализирован. Значит первый пункт отпадает. Попробуем проверить второй пункт. Тем более, что для борьбы с такими ошибками в XCode есть специальные утилиты. Такое может происходить когда объект уже уничтожен (и на него нет ссылки), но где-то осталась ссылка на этот объект (возможно закешированная), которая пытается выполнить какие-либо действия с уничтоженным объектом. Такие объекты называются объекты зомби. 

Начинаем охоту на NSZombies

Когда активирован режим охоты на зомби XCode считаем количество инициализаций и удалений объектов. При удалении сохраняется фиктивный объект, что позволяет обнаружить объекты, которые были уже удалены. Для включения переходим: Product > Scheme > Edit Scheme.

На вкладке Diagnostics включаем Enable Zombie Objects.

Enable Zombie Objects

На вкладке Arguments в блок Environment добавляем NSZombieEnabled со значением YES.

NSZombieEnabled

Уже теперь XCode будет помогать нам в отлове этих мерзких зомбаков. Но мы пойдем дальше.

Instruments и Zombies

Откроем сессию в Instruments и выберем элемент зомби.

поиск зомби в XCode Instruments

Запустим сессию и воспроизведем ошибку. В нужный момент Instruments выдаст флаг о том, что объект зомби найден. Это часть победы!

Найден объект зомби

Нажав на флаг, увидим сообщение о классе, который работает не так как нужно.

Объект зомби найден

Получаем необходимую информацию о том, кто на самом деле зомби.

зомби

Из этого окна можно перейти в код. Код совпал с тем, что нам сказал XCode. Далее нужно всего лишь найти, где бага.

Информация о зомби XCode Zombie Object

Ошибка была в делегатах этого контола. При deinit класса, в котором используется этот контрол нужно обнулить делегаты.

deinit {
    textView.delegate = nil
    textView.layoutManager.delegate = nil
}

Комментарии

comments powered by Disqus