我是Microsoft的开发人员,我是使用Xcode进行iPhone开发的新手。所以,我正在读一本书,并通过示例尝试自学如何使用Objective-C编写iPhone应用程序。到目前为止,一切都很顺利,但偶尔我会在运行时遇到通用的'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编译器中使构建失败。是否有编译器设置我可以更改以在构建这些错误时使构建失败?
首先,打开~/.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
)。我个人认为:
(来源:lyndir.com)
您现在应该在代码中遇到大多数错误的编译器警告,并且在您修复代码之前编译器不会让您运行代码。当事情确实越过编译器的鼻子时,你应该能够轻松找到问题,GDB在一个方便的位置破解。
你也应该看看NSZombie*
。这些是环境变量,非常便于早期破坏不良内存分配或访问情况。例如; wih NSZombieEnabled
什么都不会真正被释放;在dealloc上它会被_NSZombie
覆盖并且如果你再次尝试访问这个解除分配的内存(取消引用一个解除分配的指针),你将在GDB中获得一些东西,而不是正常的调用,只是随机发出数据(当然,这不是你想要的)。有关这方面的更多信息,请参阅http://www.cocoadev.com/index.pl?NSZombieEnabled。
始终使用-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
这将告诉您代码中抛出异常的行。
拼写错误的参数通常应该导致“警告:这样的对象不响应选择器x”在所讨论的行中为黄色。我相信默认情况下这是打开的,因为我没有必要更改任何编译器设置来查看这些。
此外,当我遇到未捕获的异常时,放入gdb控制台(应该在执行应用程序时出现)并输入以下内容以获取所有线程的回溯有时是有益的:
t a bt
您所做的不是编译时错误,因为Objective-C运行时会在运行时检查对象是否可以响应您发送给它的消息。
我建议将此构建设置添加到目标或项目中:
GCC_TREAT_WARNINGS_AS_ERRORS = YES
它不是编译错误的原因是因为将编译时未知的消息发送到任何对象是完全有效的(并且任何对象都可以配置为动态处理消息)。所有方法调用实际上都是发送给对象的消息。
一般来说,如果你看到任何警告,你应该解决它们,因为在大多数情况下,它们可能会导致问题(如你所见)。这里误导的方面是,如果您编译一次文件并且它只有警告,如果您编译其他类而不更改具有警告的类,则警告将不会显示在编译器消息中。因此,您可能偶尔会“清理所有目标”并再次构建,以确保您不会错过任何警告。