【问题标题】:Debugging exception thrown in Objective-C and Xcode在 Objective-C 和 Xcode 中抛出的调试异常
【发布时间】:2010-10-17 05:37:03
【问题描述】:

我是一名长期的 Microsoft 开发人员,而且我是使用 Xcode 进行 iPhone 开发的新手。因此,我正在阅读一本书并通过示例尝试自学如何使用 Objective-C 编写 iPhone 应用程序。到目前为止一切都很好,但是,有时我会在运行时遇到通用的“objc_exception_throw”消息。发生这种情况时,很难找到此异常的来源。经过反复试验,我找到了答案。其中一个参数拼写错误。

如下所示,我在按钮中省略了第二个“t”,拼错了“otherButtonTitles”参数。

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

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

【问题讨论】:

  • 代表比我多的人应该将标题编辑为“调试和防止'objc_exception_throw'”。

标签: iphone xcode xcodebuild


【解决方案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)。就个人而言,我将其设置为:


(来源:lyndir.com)

您现在应该会收到编译器警告,因为您可能会在代码中做错大多数事情,并且编译器不会让您运行代码,直到您修复它们。当编译器发现问题时,您应该能够在方便的地方轻松找到 GDB 中断的问题。

您还应该查看NSZombie*。这些环境变量对于早期中断内存分配或访问情况不佳非常方便。例如;与NSZombieEnabled 什么都不会真正发布;在 dealloc 上,它会被_NSZombie 覆盖,如果你尝试再次访问这个释放的内存(解除对释放指针的引用),你会在 GDB 中得到一些中断,而不是像往常一样进行调用,只会发出随机数据(当然,这不是你想要的)。有关这方面的更多信息,请参阅http://www.cocoadev.com/index.pl?NSZombieEnabled。

【讨论】:

  • 注意:为了让“GCC 4.0 警告”部分出现在您的设置中(如上所示),您必须将 Base SDK 和 Active SDK 设置为设备而不是模拟器。
  • 此外,当您启用“将警告视为错误”时,您仍会像以前一样看到警告,但您会收到 1 个有点误导性的错误“Command /Developer/Platforms/iPhoneOS.platform/Developer/usr/ bin/gcc-4.0 失败,退出代码为 1"。清除所有警告后,此错误将消失。
【解决方案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

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

【讨论】:

  • 这是一个很好的建议 - 要添加的另一件事是在“objc_exception_throw”上设置一个全局断点,当您的代码执行一些引发异常的操作时,它将自动中断。
【解决方案3】:

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

我建议将此构建设置添加到您的目标或项目中:

GCC_TREAT_WARNINGS_AS_ERRORS = YES

【讨论】:

    【解决方案4】:

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

    一般来说,如果您看到任何警告,您应该解决它们,因为在大多数情况下它们会导致问题(如您所见)。这里的误导性方面是,如果您编译一次文件并且它只有警告,如果您编译其他类而不更改有警告的类,则警告不会显示在编译器消息中。因此,您可能会时不时地“清理所有目标”并重新构建以确保您没有错过任何警告。

    【讨论】:

      【解决方案5】:

      拼写错误的参数通常会在相关行以黄色显示“警告:某某对象不响应选择器 x”。我相信默认情况下这是打开的,因为我不必更改任何编译器设置即可看到这些。

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

      t a bt

      【讨论】:

      • "t a a bt" 是“thread apply all backtrace”的缩写,只是打印所有线程的回溯
      猜你喜欢
      • 2010-09-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-16
      相关资源
      最近更新 更多