2009-04-02 3 views
10

Я давно разработчик Microsoft, и я новичок в разработке iPhone с использованием XCode. Итак, я читаю книгу и просматриваю примеры, пытаясь научить себя, как писать приложение iPhone с помощью Objective-C. Тем не менее, все было хорошо, однако время от времени я сталкиваюсь с общим сообщением «objc_exception_throw» во время выполнения. Когда это произойдет, источник этого исключения очень сложно найти. После некоторых проб и ошибок я нашел свой ответ. Один из параметров был опечатан.Исключение отладки в Objective C и XCode

Как вы можете видеть ниже, я ошибся с параметром 'otherButtonTitles', оставив вторую кнопку 't' в кнопке.

UIAlertView *alert = [[UIAlertView alloc] 
         initWithTitle:@"Date and Time Selected" 
         message:message 
         delegate:nil 
         cancelButtonTitle:@"Cancel" 
         otherButonTitles:nil]; 

Причина, по которой мне потребовалось время, чтобы найти, что код был успешно выполнен. Это обычное поведение для компилятора Objective-C? Я привык к сбою сборки в компиляторе .NET, когда я делаю общую синтаксическую ошибку, подобную этой. Есть ли параметр компилятора, который я могу изменить, чтобы сделать встроенный сбой, когда я делаю эти ошибки?

+1

У кого-то больше репутации, чем я должен изменить заголовок этого на что-то вроде «Отладка и предотвращение« objc_exception_throw ». –

ответ

25

Прежде всего, откройте ~/.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 Warning Build Settings http://lhunath.lyndir.com/stuff/gcc_warnings.png

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

Вы также должны изучить NSZombie*. Это переменные среды, которые очень удобны для раннего взлома при неправильном распределении памяти или доступе. Например; wih NSZombieEnabled ничего действительно не будет выпущено; на dealloc он будет перезаписан _NSZombie, и если вы попытаетесь снова получить доступ к этой освобожденной памяти (разыменовывая освобожденный указатель), вы получите что-то, что нужно разбить в GDB, вместо того, чтобы вызов проходил, как обычно, только на случайных данные (что, конечно, не то, что вы хотели). Для получения дополнительной информации об этом см. http://www.cocoadev.com/index.pl?NSZombieEnabled.

+0

ПРИМЕЧАНИЕ. Чтобы в настройках отображались разделы «Предупреждения GCC 4.0» (как показано выше), вы должны иметь базовый SDK и Active SDK, установленные на устройстве, а не в Simulator. – rtemp

+0

Кроме того, когда вы включаете «Обработать предупреждения как ошибки», вы по-прежнему будете видеть предупреждения, как и раньше, но вы получите 1 несколько ошибочную ошибку. «Команда /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/gcc-4.0 не удалась с код выхода 1 ". Эта ошибка исчезнет, ​​когда все предупреждения будут удалены. – rtemp

8

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

Кроме того, когда я сталкиваюсь неперехваченное исключением, это иногда полезно зайти в консоль GDB (должно прийти, когда вы выполняете приложение) и введите следующую команду, чтобы получить цепочки вызовов для всех потоков:

ТАА Bt

+0

«taa bt» - это аббревиатура от «thread apply all backtrace» и просто печатает обратную линию для всех потоков. –

1

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

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

2

То, что вы сделали, не является ошибкой времени компиляции, поскольку проверка выполнения Objective-C во время выполнения проверяет, может ли объект отвечать на отправленное ему сообщение.

Я рекомендую добавить эту сборку настройки для вашей цели или проекта:

GCC_TREAT_WARNINGS_AS_ERRORS = YES 
9

Всегда использовать настройки -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 

Это скажет вам строку в вашем коде, где было исключено исключение.

+0

Это отличный совет. Еще одна вещь, которую нужно добавить, - установить глобальную точку останова на «objc_exception_throw», которая автоматически разрывается, когда ваш код делает что-то, что вызывает исключение. –

 Смежные вопросы

  • Нет связанных вопросов^_^