Исключение отладки, брошенное в Objective-C и XCode - PullRequest
10 голосов
/ 03 апреля 2009

Я долгое время являюсь разработчиком 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, когда я делаю типичную синтаксическую ошибку, подобную этой. Могу ли я изменить настройку компилятора, чтобы при сбое при сборке я не мог скомпилировать сборку?

Ответы [ 5 ]

25 голосов
/ 03 апреля 2009

Прежде всего, откройте ~/.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
(источник: lyndir.com )

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

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

9 голосов
/ 03 апреля 2009

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

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

8 голосов
/ 03 апреля 2009

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

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

т а бт

2 голосов
/ 03 апреля 2009

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

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

GCC_TREAT_WARNINGS_AS_ERRORS = YES
1 голос
/ 03 апреля 2009

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

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

...