Cocoa / iPhone: отладка ошибки EXC_BAD_ACCESS

Если вы хоть раз занимались разработкой программного обеспечения под iPhone, то наверняка встречались с ошибкой EXC_BAD_ACCESS. Отловить ее достаточно непросто, т.к. встроенный дебагер не покажет вам нужный стектрейс и тем более не подскажет, как все исправить.

Что же такое EXC_BAD_ACCESS? Мне удобнее сравнивать эту ошибку с NullPointerException в Java, т.к. возникает она в ситуации, когда вы отправляете "сообщение" объекту, который уже был выгружен из памяти (released). Например, попробуйте создать объект с помощью alloc и затем два раза подряд его "отпустить" с помощью release.

Так как же быть, если у нас достаточно большой проект с массой кода и объектов? Как проще и быстрее отловить данную ошибку? На помощь придет директива NSZombiEnabled, установленная в переменных окружения проекта. Все, что она сделает - это заставит Objective C runtime оставлять объект-пустышку за каждым выгруженным реальным объектом и в следующий раз, когда вы попытаетесь обратиться к своему выгруженному объекту, вызов пойдет именно к пустышке, которая остановит выполнение кода и выведет короткое и ясное сообщение в дебагер о том, какой объект был вызван и что за сообщение ему было отправлено. Стектрейс при этом также не будет испорчен, и сможет дать дополнительную информацию о месте баги.

2010-01-08 16:21:35.802 My Project[4833:207] *** -[NSMutableURLRequest release]: message sent to deallocated instance 0x4925f30

Чтобы установить данную переменную, откройте Xcode, меню Project --> Edit Active Executable. Далее выберите вкладку Arguments, во втором списке добавьте переменную NSZombieEnabled и поставьте ей значение YES в столбце Value. Убедитесь, что перед названием переменной стоит галка.

NSZombie

В моем примере помимо NSZombieEnabled установлены еще две переменные: NSAutoreleaseFreedObjectCheckEnabled и NSDebugEnabled. Первая предотвратит автоматическую выгрузку из памяти объектов, помеченных как autorelease в случае, когда они уже были выгружены ранее. Вторая переменная будет полезна скорее самому разработчику, т.к. ее можно будет использовать в своем коде, когда нужно, например, вывести дополнительную информацию в debug log:

if (NSDebugEnabled) {
NSLog(@"Some debug info...");
}

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

Да, часа два мучался (ну новичок я в Objective C) с этим Бэд Аксессом. Под конец набрал в Яндексе. Первый клик - Ваш пост - 10 секунд и проблема понята. Еще пару минут - и устранена в коде :) Спасибо.

спасибо за пост

спасибо, оч полезно!

Спасибо! Реально помогло найти багу.

Хороший и полезный блог у Вас получается.
Респект и уважуха!

Отправить комментарий

Image CAPTCHA
Enter the characters shown in the image.
Реклама на stremoukhov.ru: