Исключение отладки в Objective C и XCode
Я давно разработчик Microsoft, и я новичок в разработке iPhone, используя XCode. Итак, я читаю книгу и просматриваю примеры, пытаясь научить себя писать приложение iPhone с помощью Objective-C. Тем не менее, все было хорошо, однако время от времени я запускаю общее сообщение objc_exception_throw
во время выполнения. Когда это произойдет, источник этого исключения очень сложно найти. После некоторых проб и ошибок я нашел свой ответ. Один из параметров был опечатан.
Как вы можете видеть ниже, я ошибся с параметром "otherButtonTitles", оставив вторую кнопку "t" в кнопке.
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:@"Date and Time Selected"
message:message
delegate:nil
cancelButtonTitle:@"Cancel"
otherButonTitles:nil];
Причина, по которой мне пришлось найти время, - это то, что код успешно создан. Это нормальное поведение для компилятора Objective-C? Я привык к сбою сборки в компиляторе .NET, когда я делаю общую синтаксическую ошибку, подобную этой. Есть ли параметр компилятора, который я могу изменить, чтобы сделать встроенный сбой, когда я делаю эти ошибки?
Ответы
Ответ 1
Прежде всего, откройте ~/.gdbinit
(файл .gdbinit
в вашем домашнем каталоге - да, начинается с точки) и поместите его в него:
fb -[NSException raise]
fb objc_exception_throw
fb malloc_error_break
Это приведет к инициализации GDB с тремя точками останова по умолчанию, когда они появятся, GDB остановит ваше приложение и покажет вам трассировку стека. Это очень хорошо интегрировано с Xcode, поэтому вы сможете хорошо пройтись по вашему коду, щелкнув элементы трассировки стека, как только произойдет какое-то исключение, или сбой malloc.
Затем откройте панель Get Info
в своем проекте (или выберите свой проект (верхний элемент в Groups & Files
) и нажмите cmd-i
), перейдите на вкладку Build
и установите для проекта Base SDK
значение Device - iPhone OS [someversion]
. Прокрутите до конца и найдите раздел GCC 4.0 - Warnings
. Там; включите столько предупреждений, сколько вам удобно, но обязательно включите Treat Warnings as Errors
(это эквивалент GCC_TREAT_WARNINGS_AS_ERRORS
). Лично я решил:
Параметры настройки предупреждения GCC http://lhunath.lyndir.com/stuff/gcc_warnings.png
Теперь вы должны получать предупреждения компилятора для большинства вещей, которые вы можете сделать неправильно в коде, и компилятор не позволит вам запускать код до тех пор, пока вы их не исправите. Когда что-то проходит мимо носа компилятора, вы должны легко найти проблему с разрывом GDB в удобном месте.
Вы также должны изучить NSZombie*
. Это переменные среды, которые очень удобны для раннего взлома при неправильном распределении памяти или доступе. Например; wih NSZombieEnabled
ничто действительно не будет выпущено; на dealloc он будет перезаписан с помощью _NSZombie
, и если вы попытаетесь снова получить доступ к этой освобожденной памяти (разыменовывая освобожденный указатель), вы получите что-то, что нужно разбить в GDB, вместо того, чтобы вызов проходил, как обычно, только выдается по случайным данным (что, конечно, не то, что вы хотели). Для получения дополнительной информации об этом см. http://www.cocoadev.com/index.pl?NSZombieEnabled.
Ответ 2
Всегда используйте параметр -Werror
GCC (GCC_TREAT_WARNINGS_AS_ERRORS = YES
). У вас никогда не должно быть предупреждений в коде, и это пример, когда предупреждение является критичной ошибкой.
Кроме того, если вы получите objc_exception_throw
, переключитесь на консоль (Command-shift-R) и найдите первый "низкий" номер.
2009-04-01 13:25:43.385 CrashExample[41720:20b] Stack: (
2528013804,
2478503148,
2528036920,
2528053460,
2358032430,
11076,
11880,
816174880,
345098340,
145973440,
816174880,
)
В этом случае это будет "11076". Введите тип консоли:
info line *11076
Это скажет вам строку в вашем коде, где было исключено исключение.
Ответ 3
Ошибочные параметры обычно должны приводить к "Предупреждение: такой-то-то объект не отвечает селектору x" желтым цветом в соответствующей строке. Я считаю, что это по умолчанию, так как мне не нужно было изменять какие-либо настройки компилятора, чтобы увидеть их.
Кроме того, когда я сталкиваюсь с неперехваченным исключением, иногда полезно перейти в консоль gdb (должен появиться при выполнении вашего приложения) и ввести следующее для получения обратных трасс для всех потоков:
t a a bt
Ответ 4
То, что вы сделали, не является ошибкой времени компиляции, поскольку среда выполнения Objective-C проверяет во время выполнения, если объект может ответить на отправленное ему сообщение.
Я рекомендую добавить этот параметр сборки в свою цель или проект:
GCC_TREAT_WARNINGS_AS_ERRORS = YES
Ответ 5
Причина, по которой это не ошибка компиляции, заключается в том, что она абсолютно корректна для отправки сообщения, неизвестного во время компиляции, любому объекту (и любой объект может быть настроен так, чтобы обрабатывать сообщения также динамически). Все вызовы методов - это действительно сообщения, отправляемые объектам.
В общем, если вы видите какие-либо предупреждения, вы должны обращаться к ним, так как в большинстве случаев они могут привести к проблемам (как вы видели). Обманчивый аспект здесь заключается в том, что если вы скомпилируете файл один раз и у него есть только предупреждения, если вы скомпилируете другие классы без внесения изменений в класс с предупреждениями, предупреждение не будет отображаться в сообщениях компилятора. Поэтому время от времени вы можете захотеть "очистить все цели" и снова построить, чтобы убедиться, что вы не пропустили никаких предупреждений.