【问题标题】:Why does assert simply terminate a program compiled for iPhone?为什么断言只是终止为 iPhone 编译的程序?
【发布时间】:2011-01-01 08:09:51
【问题描述】:

我正在调试一个严重使用 assert() 的 iPhone 应用程序(Xcode、Objective-C++ 和设备模拟器)。在某些情况下,断言失败只会终止应用程序,而不是像我预期的那样闯入调试器。

我通过实现我自己的 kinda-assert 来解决:

#define AssertLite(b) if(!(b)) {asm {int 3}}

(省略绒毛),但我想知道是否有人遇到过这种情况。我无法确定它何时中断以及何时终止的模式。代码没有线程化;它所做的一切都是在事件处理程序中完成的。

为什么会发生这种情况,如何让 vanilla assert() 表现得像一个条件断点?

【问题讨论】:

    标签: iphone xcode debugging assert objective-c++


    【解决方案1】:

    首先,由于您正在开发 iPhone 应用程序,因此您可能应该使用 NSAssert() 而不是普通的 BSD 断言函数。

    例如NSAssert(the_object, @"NIL object encountered");

    如果断言失败,NSAssert 宏将抛出一个 Objective-C 异常 (NSInternalInconsistencyException)。

    由于您的目标是中断异常,下一步是让 Xcode 调试器中断 Objective-C 异常。无论如何,这可能是一件好事。

    在断点窗口(运行->显示->断点菜单项)中,单击“双击符号”以输入符号-[NSException raise]

    最后要小心的是,NSAsserts 不会在发布版本中编译出来。这意味着您必须准备好处理应用程序中的异常,或者您需要创建自己的宏以在发布版本中编译出来。

    这是我用来编译运行时代码中的断言的宏(请注意,我随后在我的代码中使用 HMAssert 而不是 NSAssert):

    #ifdef DEBUG
    #   define HMAssert(A,B) NSAssert(A,B)
    #else
    #   define HMAssert(A,B)
    #endif
    

    这需要定义一个 DEBUG 预处理器宏。设置方法如下:

    1. 在 Xcode 中右键单击您的项目。这将是左侧面板中列出您的项目文件的顶部项目
    2. 从弹出的上下文菜单中选择“获取信息”。
    3. 转到“构建”选项卡。
    4. 确保“配置”设置为“调试”。
    5. 在“GCC 4.2 - 预处理”下的“预处理器宏”旁边的字段中键入 DEBUG。

    【讨论】:

    • Raw NSAssert 不是一个选项,因为代码库需要针对非 Apple 平台进行交叉编译。如果我开始#defining 基本的assert(),我还不如自己动手,反正我已经开始这样做了。不过感谢您的提示。
    【解决方案2】:

    首先,如果您在断点导航器 (⌘6) 中“添加异常断点...”,调试器将在 NSAssert 失败时停止,让您查看堆栈并了解哪里出了问题。

    您应该使用标准的 NSAssert。如果你正确使用它,你不需要手动创建很多东西——Mike 提到的所有东西都类似于默认的 NSAssert 实现。

    您应该在预编译头文件中设置 NS_BLOCK_ASSERTIONS 来运行发布配置(按照 Mike 的步骤),以禁用断言。如果您需要更多关于为什么这样做的信息,请查看:http://myok12.wordpress.com/2010/10/10/to-use-or-not-to-use-assertions/

    【讨论】:

      【解决方案3】:

      在 Xcode 4 和新的 iOS 中,NSAssert 实际上可能采用可变参数列表。这对于将一些值与断言一起记录可能很有用。编译断言(见上面 Mike 的回答)可以这样定义:

      #ifdef DEBUG
      #   define DAssert(A, B, ...) NSAssert(A, B, ##__VA_ARGS__);
      #else
      #   define DAssert(...);
      #endif
      

      此外,不再有运行 → 显示 → 断点菜单项。请参阅this post 以设置 Xcode 4 以中断如上定义的断言。

      【讨论】:

        【解决方案4】:

        有一次我看到一次与 assert() 调用不同的行为。这是因为编译器在构建过程的不同部分选择了不同的宏定义。

        在理顺包含路径后,它们的工作方式都相同。

        【讨论】:

          猜你喜欢
          • 2011-02-28
          • 2016-07-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-08-04
          • 1970-01-01
          相关资源
          最近更新 更多