Это касается только Xcode 4 и более поздних версий:
ПЕРВЫЙ ТРУДОЁМКИЙ СПОСОБ: прицепить либы к дереву проекта намертво (вероятно можно и мышкой добавить нужные либы из Finder-папки перетаскивая их прямо в дерево проекта), но я делал это выходя в свойства проекта, потом переключался на вкладку Target, выбирал там Build Phases -> Link Binary With Libraries.
Этот первый способ плох тем, что Xcode порой глючит, и не в состоянии отличить дебаг-либу от релизной и может прицеплять дебаг-либу при релизной сборке приложения. Поэтому мне пришлось написать shell-скрипты, которые прятали в Temp-папки те либы, которые мне мешали и shell-скрипты для возвращения этих либ на прежние места. То есть перед Release-сборкой приложения все дебаг-либы можно аккуратно убрать одним запуском скрипта - при этом эти либы окрасятся в тревожный красный цвет в дереве проекта, но пусть это вас не пугает - приложение будет исправно собираться с оставшимися релизными либами.
НОВЫЙ ХОРОШИЙ СПОСОБ (пока плохо мной оттестирован): не добавлять либы первым способом в дерево проекта. Добавьте пути к нужным либам (включая имена файлов этих собранных либ) в настройках проекта и настройках таргета -> Build Settings -> Linking -> Other Linker Flags (в подраздел Debug добавьте пути к дебаг-либам, в подраздел Release - к релиз-либам). Кроме того, вы можете в Debug/Release подразделы добавить вложенные подразделы для разных таргетов (для симуляторов и девайсов) - для этого найдите + кнопку справа внизу "Add Build Settings", нажмите на неё и выберите "Add Conditional Settings" (укажите пути для симуляторных и девайсовских дебаг/релиз либ).
Показаны сообщения с ярлыком debug. Показать все сообщения
Показаны сообщения с ярлыком debug. Показать все сообщения
вторник, 22 января 2013 г.
четверг, 1 ноября 2012 г.
Как отключать все вызовы NSLog для release-сборки
Опыт показывает, что перед release-сборкой очередной версии (для
отправки в AppStore) комментировать десятки или даже сотни отладочных
выводов в консоль слишком утомительно, да и не всегда полезно (некоторые
выводы в консоль могут ещё пригодиться). Добавьте удобную макрофункцию
где-нибудь в общий заголовок проекта (который включаете почти везде,
например пусть это будет AppMacros.h).
#ifdef DEBUG
#define DLog(f, ...) NSLog(f, ## __VA_ARGS__)
#else
#define DLog(f, ...)
#endif
Теперь с помощью Find and Replace замените все NSLog на DLog. Если в некоторых исходниках вылезут ошибки компиляции, то добавьте в эти исходники #include "AppMacros.h"
#ifdef DEBUG
#define DLog(f, ...) NSLog(f, ## __VA_ARGS__)
#else
#define DLog(f, ...)
#endif
Теперь с помощью Find and Replace замените все NSLog на DLog. Если в некоторых исходниках вылезут ошибки компиляции, то добавьте в эти исходники #include "AppMacros.h"
пятница, 30 апреля 2010 г.
Как выяснить причину EXC_BAD_ACCESS в Xcode
Нашёл интересную статью (на английском) на http://www.codza.com/how-to-debug-exc_bad_access-on-iphone (там это приводится с рисунками и комментариями читателей).
НАЧАЛО ЦИТАТЫ.
EXC_BAD_ACCESS. Debugging this one is on par with figuring out why the wife says “not tonight, honey.” And they are equally unfortunate situations.
Let’s see what we can do about EXC_BAD_ACCESS.
EXC_BAD_ACCESS happens when a message is sent to an object that has already been released. By the time the error is caught, the call stack is usually gone especially if dealing with multiple threads.
How nice would it be to keep a dummy around after the object is released that could stop execution, tell us what message was sent and show us the call stack… well, there’s a way to do just that.
If you set the NSZombieEnabled environment variable, the Objective C runtime will leave a dummy object behind for every deallocated object. When the zombie object is called, execution stops and you can see the message that was sent to the object and the call stack that tells you where the message came from (it doesn’t tell you where you over released the object, but knowing where the object is called from should get you pretty close to the problem.)
To set this variable, go to the info panel of the executable in xcode, and create a new environment variable in the arguments tab by clicking the plus sign in the lower left corner of the window. Name the variable NSZombieEnabled, type YES for the value and make sure that the checkbox is selected.
set NSZombieEnabled variable
set NSZombieEnabled variable
Go ahead and run your program now (in debug mode, because you need the stack information.) When the over released object is accessed, you get an error message similar to this (xcode debug view):
2009-03-30 02:30:36.172 ninjaJumper[3997:20b] *** -[GameLayer retain]: message sent
to deallocated instance 0x59bf670
This shows the class of the object (GameLayer) and the message sent (retain).
Let’s take a look at the stack now:
call stack
call stack
The methods printed in bold are in your code, the others are in some other API. Here you can see that the object was accessed from [Director touchesBegan:withEvent], where an array was copied (most likely the over released object was in the array.)
This information should get you pretty close to the problem.
Once the problem is fixed, make sure that the NSZombieEnabled variable is disabled. You don’t need to delete it, but make sure that the checkbox is unchecked:
NSZombie disabled
NSZombie disabled
Now about the wife. Good luck there. Try a box of chocolate or load the dishwasher for a couple days.
КОНЕЦ ЦИТАТЫ.
К СОЖАЛЕНИЮ, ДАННЫЙ СОВЕТ ПОЗВОЛЯЕТ ОТСЛЕЖИВАТЬ ИМЕНА Objective C КЛАССОВ. Я ТОЛЬКО ЧТО СДЕЛАЛ ТЕСТОВОЕ ПРИЛОЖЕНИЕ, В КОТОРОМ ПОЛЕЗНЫЕ ОТЛАДОЧНЫЕ СООБЩЕНИЯ ВЫВОДЯТСЯ В КОНСОЛЬ ТОЛЬКО КАСАЕМО Objective C КЛАССОВ:
TestClass *testObj = [[TestClass alloc] init];
[testObj release]; // уничтожили объект перед попыткой использования
[testObj printMsg];
В этом случае в консоль будет выводиться информация
2010-04-28 13:02:08.030 ZombieTest[1353:207] *** -[TestClass printMsg]: message sent to deallocated instance 0x3924880)
В случае же с C++ классом:
TestCppClass *tcpp = new TestCppClass();
delete tcpp;
tcpp = 0;
tcpp- >PrintMsg(); // удивительно, но это работает (на экран выводится тестовое сообщение, так как вероятно функция-член класса способна работать и без создания объекта - ЭТО ЧТО, ОЧЕРЕДНОЙ БАГ Xcode?)
delete tcpp; // тем не менее здесь код спотыкается, так как пытаемся уничтожить объект повторно
в консоль выводится то же самое что и без применения совета из приведённой статьи):
2010-04-28 13:04:45.242 ZombieTest[1476:207] TestClass --- printMsg
ZombieTest(1476,0xa0a7b4e0) malloc: *** error for object 0x3917160: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
НАЧАЛО ЦИТАТЫ.
EXC_BAD_ACCESS. Debugging this one is on par with figuring out why the wife says “not tonight, honey.” And they are equally unfortunate situations.
Let’s see what we can do about EXC_BAD_ACCESS.
EXC_BAD_ACCESS happens when a message is sent to an object that has already been released. By the time the error is caught, the call stack is usually gone especially if dealing with multiple threads.
How nice would it be to keep a dummy around after the object is released that could stop execution, tell us what message was sent and show us the call stack… well, there’s a way to do just that.
If you set the NSZombieEnabled environment variable, the Objective C runtime will leave a dummy object behind for every deallocated object. When the zombie object is called, execution stops and you can see the message that was sent to the object and the call stack that tells you where the message came from (it doesn’t tell you where you over released the object, but knowing where the object is called from should get you pretty close to the problem.)
To set this variable, go to the info panel of the executable in xcode, and create a new environment variable in the arguments tab by clicking the plus sign in the lower left corner of the window. Name the variable NSZombieEnabled, type YES for the value and make sure that the checkbox is selected.
set NSZombieEnabled variable
set NSZombieEnabled variable
Go ahead and run your program now (in debug mode, because you need the stack information.) When the over released object is accessed, you get an error message similar to this (xcode debug view):
2009-03-30 02:30:36.172 ninjaJumper[3997:20b] *** -[GameLayer retain]: message sent
to deallocated instance 0x59bf670
This shows the class of the object (GameLayer) and the message sent (retain).
Let’s take a look at the stack now:
call stack
call stack
The methods printed in bold are in your code, the others are in some other API. Here you can see that the object was accessed from [Director touchesBegan:withEvent], where an array was copied (most likely the over released object was in the array.)
This information should get you pretty close to the problem.
Once the problem is fixed, make sure that the NSZombieEnabled variable is disabled. You don’t need to delete it, but make sure that the checkbox is unchecked:
NSZombie disabled
NSZombie disabled
Now about the wife. Good luck there. Try a box of chocolate or load the dishwasher for a couple days.
КОНЕЦ ЦИТАТЫ.
К СОЖАЛЕНИЮ, ДАННЫЙ СОВЕТ ПОЗВОЛЯЕТ ОТСЛЕЖИВАТЬ ИМЕНА Objective C КЛАССОВ. Я ТОЛЬКО ЧТО СДЕЛАЛ ТЕСТОВОЕ ПРИЛОЖЕНИЕ, В КОТОРОМ ПОЛЕЗНЫЕ ОТЛАДОЧНЫЕ СООБЩЕНИЯ ВЫВОДЯТСЯ В КОНСОЛЬ ТОЛЬКО КАСАЕМО Objective C КЛАССОВ:
TestClass *testObj = [[TestClass alloc] init];
[testObj release]; // уничтожили объект перед попыткой использования
[testObj printMsg];
В этом случае в консоль будет выводиться информация
2010-04-28 13:02:08.030 ZombieTest[1353:207] *** -[TestClass printMsg]: message sent to deallocated instance 0x3924880)
В случае же с C++ классом:
TestCppClass *tcpp = new TestCppClass();
delete tcpp;
tcpp = 0;
tcpp- >PrintMsg(); // удивительно, но это работает (на экран выводится тестовое сообщение, так как вероятно функция-член класса способна работать и без создания объекта - ЭТО ЧТО, ОЧЕРЕДНОЙ БАГ Xcode?)
delete tcpp; // тем не менее здесь код спотыкается, так как пытаемся уничтожить объект повторно
в консоль выводится то же самое что и без применения совета из приведённой статьи):
2010-04-28 13:04:45.242 ZombieTest[1476:207] TestClass --- printMsg
ZombieTest(1476,0xa0a7b4e0) malloc: *** error for object 0x3917160: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
Ярлыки:
c++,
debug,
debugger,
exc_bad_access,
iphone,
nszombieenabled,
objective c,
xcode
Подписаться на:
Сообщения (Atom)