Iphone 在Objective-C和Xcode中引发调试异常

Iphone 在Objective-C和Xcode中引发调试异常,iphone,xcode,xcodebuild,Iphone,Xcode,Xcodebuild,我是一名长期的微软开发人员,对使用Xcode开发iPhone还不熟悉。因此,我正在阅读一本书,并通过一些示例来教自己如何使用Objective-C编写iPhone应用程序。到目前为止,一切都很好,但是,偶尔我会在运行时遇到通用的“objc\u exception\u throw”消息。发生这种情况时,很难找到此异常的来源。经过反复试验,我找到了答案。其中一个参数拼写错误 正如您在下面看到的,我将按钮中的第二个“t”省略,从而拼错了“otherButtonTiles”参数 UIAlertView

我是一名长期的微软开发人员,对使用Xcode开发iPhone还不熟悉。因此,我正在阅读一本书,并通过一些示例来教自己如何使用Objective-C编写iPhone应用程序。到目前为止,一切都很好,但是,偶尔我会在运行时遇到通用的“
objc\u exception\u throw
”消息。发生这种情况时,很难找到此异常的来源。经过反复试验,我找到了答案。其中一个参数拼写错误

正如您在下面看到的,我将按钮中的第二个“t”省略,从而拼错了“otherButtonTiles”参数

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

我花时间去寻找的原因是代码构建成功。这是Objective-C编译器的正常行为吗?当我出现这样的常见语法错误时,我习惯于在.NET编译器中生成失败。当我犯这些错误时,是否有编译器设置可以更改以使生成失败?

拼写错误的参数通常会导致相关行中出现黄色的“警告:某某对象不响应选择器x”。我相信这在默认情况下是启用的,因为我不必更改任何编译器设置来查看这些设置

此外,当我遇到一个未捕获的异常时,有时进入gdb控制台(在执行应用程序时应该出现)并键入以下内容以获取所有线程的回溯是有益的:


它之所以不是编译错误,是因为向任何对象发送编译时未知的消息是完全有效的(并且任何对象也可以配置为动态处理消息)。所有方法调用实际上都是发送给对象的消息


一般来说,如果您看到任何警告,您应该解决它们,因为在大多数情况下,它们可能会导致问题(如您所见)。这里的误导之处在于,如果编译一个文件一次,它只有警告,如果编译其他类而不更改有警告的类,则警告不会显示在编译器消息中。因此,您可能偶尔希望“清除所有目标”,并再次构建,以确保不会错过任何警告。

您所做的不是编译时错误,因为Objective-C运行时会在运行时检查对象是否能够响应您发送给它的消息

我建议将此生成设置添加到目标或项目中:

GCC_TREAT_WARNINGS_AS_ERRORS = YES

始终使用
-Werror
GCC设置(
GCC\u将警告视为错误=YES
)。您的代码中不应该有警告,这是一个警告是严重错误的示例

此外,如果您得到一个
objc\u异常\u抛出
,请切换到控制台(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

这将告诉您代码中引发异常的那一行。

首先,打开
~/.gdbinit
(这是主目录中名为
.gdbinit
的文件-是的,以点开头)并将其放入其中:

fb -[NSException raise]
fb objc_exception_throw
fb malloc_error_break
这将使用三个默认断点初始化GDB,当它们出现时,GDB将停止应用程序并向您显示堆栈跟踪。这与Xcode集成得非常好,所以当某个地方发生异常或malloc失败时,您可以通过单击堆栈跟踪元素很好地遍历代码

然后,打开项目上的
Get Info
面板(或选择项目(在
组和文件中的顶部项目)并点击
cmd-i
),转到
Build
选项卡,将项目的
Base SDK
设置为
设备-iPhone OS[someversion]
。滚动到底部,找到GCC 4.0-警告部分。那里启用尽可能多的警告,但请确保启用
将警告视为错误
(这相当于
GCC\u将警告视为错误
)。就我个人而言,我将其设置为:


(来源:)

您现在应该会收到针对代码中可能出现错误的大部分内容的编译器警告,并且在您修复它们之前,编译器不会让您运行代码。当事情真的越过编译器的鼻子时,您应该能够在一个方便的位置轻松地发现GDB中断的问题


您还应该查看
NSZombie*
。这些是环境变量,对于早期中断坏内存分配或访问情况非常方便。例如;如果NSZombieEnabled
;在dealloc上,它将被
\n僵尸
覆盖,如果您再次尝试访问此解除分配的内存(解除对解除分配的指针的引用),您将在GDB中得到一些东西来中断,而不是像正常情况一样通过调用,只在随机数据上发出(当然,这不是您想要的)。有关这方面的更多信息,请参阅。

这是一个很好的建议-另一个需要添加的内容是在“objc_exception_throw”上设置一个全局断点,当代码执行引发异常的操作时,该断点将自动断开。注意:为了在设置中显示“GCC 4.0警告”部分(如上所示)您必须将基本SDK和活动SDK设置为设备,而不是模拟器。此外,当启用“将警告视为错误”时,您仍然会像以前一样看到警告,但您会得到1个有点误导性的错误“Command/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/gcc-4.0失败,退出代码为1”。清除所有警告后,此错误将消失。“t a bt”是“thread apply all backtrace”的缩写,只需为所有Threads打印一个backtrace,其重复次数超过我应该编辑的次数。此标题类似于“调试和防止'objc_exception_throw'”。