【问题标题】:Break on EXC_BAD_ACCESS in Xcode?在 Xcode 中打破 EXC_BAD_ACCESS?
【发布时间】:2010-12-09 23:23:31
【问题描述】:

我是 iPhone 开发和 Xcode 的新手,不知道如何开始对 EXC_BAD_ACCESS 信号进行故障排除。如何让 Xcode 在导致错误的确切行中断?


我似乎无法让 Xcode 在导致问题的行上停止,但我确实在调试控制台中看到以下行:

10 月 25 日星期日 15:12:14 测试项目[1289]: CGContextSetStrokeColorWithColor: 无效的上下文

10 月 25 日星期日 15:12:14 测试项目[1289]: CGContextSetLineWidth: 无效的上下文

10 月 25 日星期日 15:12:14 测试项目[1289]: CGContextAddPath: 无效的上下文

10 月 25 日星期日 15:12:14 测试项目[1289]: CGContextDrawPath: 无效的上下文

2009-10-25 15:12:14.680 LanderTest[1289:207] *** -[CFArray objectAtIndex:]: 消息发送到 释放实例 0x3c4e610

现在,我正在尝试绘制从 UIGraphicsGetCurrentContext() 检索到的上下文并传递给我想要绘制的对象。


进一步的试错调试,我发现NSMutableArray 我的班级有一个属性是一个僵尸。我进入了课程的init 函数,这是我使用的代码:

if ((self = [super init])) {
        NSMutableArray *array = [NSMutableArray array];
        self.terrainBlocks = array;
        [array release];
    }
    return self;    
}

我删除了[array release] 行,它不再给我EXC_BAD_ACCESS 信号,但我现在对它为什么起作用感到困惑。我认为当我使用该属性时,它会自动为我保留它,因此我应该从init 中释放它,这样我就不会泄漏。我对它的工作原理感到非常困惑,我读过的所有指南和 Stackoverflow 问题只会让我更加困惑如何在我的 init 方法中设置属性。对于哪种方式最好,似乎没有共识。

【问题讨论】:

  • 不管怎样,在 SO(或 Google)上搜索该错误并不会完全显示为空...stackoverflow.com/search?q=exc_bad_access
  • FWIW,我进行了搜索,但没有找到任何帮助我让 XCode 停止在导致 EXC_BAD_ACCESS 的行上的东西。即使在打开 NSZombieEnabled 和 Build and Debug 之后,XCode 也没有显示导致错误的行。
  • 稍微相关:stackoverflow.com/questions/1027658/… 基本相同的错误,但感谢 NSTimer。
  • 该属性是retained 吗?如果是,你应该release,如果不是,你不应该。
  • Pål,他不应该,因为无论哪种方式,[NSMutableArray array]都会返回一个自动释放的NSMutableArray实例,所以你不必担心它的内存管理。

标签: iphone objective-c xcode debugging exc-bad-access


【解决方案1】:

对于任何 EXC_BAD_ACCESS 错误,您通常会尝试向已释放的对象发送消息。追踪这些的最佳方法是使用NSZombieEnabled

这是通过从不实际释放对象来实现的,而是将其包装为“僵尸”并在其中设置一个标志,表明它通常会被释放。这样,如果您再次尝试访问它,它仍然会在您出错之前知道它是什么,并且通过这些信息,您通常可以回溯以查看问题所在。

当调试器有时会发现任何有用的信息时,它尤其有助于后台线程。

非常重要的注意事项但是,您需要 100% 确保这仅在您的调试代码中,而不是在您的分发代码中。因为什么都没有发布,所以你的应用程序会泄漏、泄漏和泄漏。为了提醒我这样做,我把这个日志放在我的 appdelegate 中:

if(getenv("NSZombieEnabled") || getenv("NSAutoreleaseFreedObjectCheckEnabled"))
  NSLog(@"NSZombieEnabled/NSAutoreleaseFreedObjectCheckEnabled enabled!");

如果您需要帮助找到确切的行,请执行构建和调试 (CMD-Y) 而不是构建和运行 (CMD-R )。当应用程序崩溃时,调试器会准确显示哪一行,结合 NSZombieEnabled,您应该能够准确找出原因。

【讨论】:

  • XCode 仍然没有在导致错误的行上停止,但我已经用我在调试控制台中看到的信息更新了问题。
  • 这很有帮助,但可能会产生误导,因为无论 env 变量的实际值如何,getenv("NSZombieEnabled") 都将为真(非零)。试试这个: char* szZombie = getenv("NSZombieEnabled"); if (szZombie && 0 == strcasecmp(szZombie, "YES")) { NSLog(@"NSZombieEnabled enabled!"); }
  • 这完全取决于您如何设置变量。不使用僵尸时我将其完全删除。
  • @coneybeare 到 NSZombieEnabled 的链接已失效(未找到 404)。
【解决方案2】:

关于您的阵列。线

NSMutableArray *array = [NSMutableArray array];

实际上并没有给你一个保留对象,而是一个自动释放对象。它可能会保留在下一行,但你不应该在第三行释放它。见this

这是基本规则:

如果您使用名称以“alloc”或“new”开头或包含“copy”的方法(例如,alloc、newObject 或 mutableCopy)创建对象,或者向其发送保留消息。您有责任放弃使用 release 或 autorelease 拥有的对象的所有权。其他任何时候您收到物品时,都不得释放它。

【讨论】:

  • 谢谢。出于某种原因,我认为[NSMutableArray array] 就像allocinit,不是一种方便的方法。我敢肯定,我迟早会掌握的。
  • @jasonh,两者兼而有之。按照惯例,像这样的类方法本质上是allocinit 的串联。但是返回的对象是自动释放的,因此您需要保留结果(本质上是从分配它的类中声明对它的所有权)。
  • 所以,基本上 [[NSMutableArray array] retain] 是一种无需键入 [[NSMutable alloc] init] 的便捷方法? ;)
【解决方案3】:

在 Xcode 4 中,您可以通过单击方案下拉菜单(左上角,停止按钮旁边)-> 编辑方案 -> 诊断选项卡 -> 启用僵尸对象来启用僵尸

【讨论】:

    【解决方案4】:

    Xcode/gdb 总是在EXC_BAD_ACCESS 上中断,你只需要在调用堆栈上查找触发它的代码。

    请注意,autoreleased 对象通常会发生此类错误,这意味着问题的最终原因不会出现在触发 EXC_BAD_ACCESS 的调用堆栈中。这时候 NSZombieEnabled 和 NSAutoreleaseFreedObjectCheckEnabled 就派上用场了。

    【讨论】:

      【解决方案5】:

      旧线程的新答案...在 XCode 4 中,诊断 EXC_BAD_ACCESS 异常的最有效方法是使用 Instruments 来分析您的应用程序(从 XCode 单击 Product/Profile 并选择 Zombies)。这将帮助您识别发送到已释放对象的消息。

      【讨论】:

      • 感谢您的回答,我发现 Instruments 真的很有帮助。对于其他有这个问题的人,我强烈推荐它。它还显示了引用计数随堆栈跟踪而变化的代码行。没有它真的很难找到问题!我认为这个答案比接受的答案更好,仅 NSZombieEnabled 仅在发生无效访问时向您显示,但它不能帮助您找出原因。
      【解决方案6】:

      来自斯坦福 CS193P 课程:如果您为符号objc_exception_throw 添加断点(手动,通过编辑断点),您可以更好地了解问题所在 - 让事情继续到调试器停止的点本身往往会掩盖事物并搞砸堆栈跟踪。当您在 objc_exception_throw 中停止时,您通常可以回顾究竟是什么访问/操作导致了您的问题。

      【讨论】:

      • 是的,但是他在段错误之前抛出了一个越界异常,这绝对是一个错误,很可能会导致崩溃。
      【解决方案7】:

      另一种有用的方法是设置断点,在异常发生后直接触发:

      打开断点窗口(运行-显示-断点)并添加两个符号断点,分别称为“objc_exception_throw”和“[NSException raise]”

      发件人:http://blog.emmerinc.be/index.php/2009/03/19/break-on-exception-in-xcode/

      【讨论】:

        【解决方案8】:

        只是想为来自网络的其他人添加,寻找相同错误但错误不同的解决方案。在我的情况下,当我尝试实例化 NSDictionary 时,我遇到了同样的错误,其中我忘记在我的键前添加“@”的键名有错字:

        NSDictionary *dic = [NSDictionary dictionaryWithObjectsAndKeys: myObj1, @"goodKey", myObj2, "badkey @ is missing in front", nil];
        

        【讨论】:

          【解决方案9】:

          我希望我没有错过相同的答案,但我发现某些项目可能会抛出此错误,因为在旧 iOS 版本的模拟器上运行可能与项目依赖项或框架不兼容。我一直在追逐其中一个,然后才意识到它只是发生在 - 较旧的 - 模拟器版本中,例如 iPhone 4S,该应用程序甚至不应该尝试支持。

          如果能收到更详细的错误消息会很高兴,但我想这是它起源的框架的责任......无论如何,这是一个相当常见的搜索着陆,也许这会帮助一些人搞砸和我发现自己一样糟糕。

          【讨论】:

            【解决方案10】:

            在启用僵尸之前,我建议首先摆脱所有警告(如果有的话)。没有 return 的非 void 函数等简单的事情可能会导致此错误。如果您没有警告,请按照其他答案的建议继续。

            【讨论】:

            • 除非你确定你的警告是无害的。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2012-02-26
            • 1970-01-01
            • 2020-03-18
            • 2019-02-26
            • 2014-11-15
            • 2020-02-24
            • 1970-01-01
            相关资源
            最近更新 更多