46

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


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

10 月 25 日星期日 15:12:14 jasonsmacbook TestProject[1289]:CGContextSetStrokeColorWithColor:无效上下文

10 月 25 日星期日 15:12:14 jasonsmacbook TestProject[1289]:CGContextSetLineWidth:无效上下文

10 月 25 日星期日 15:12:14 jasonsmacbook TestProject[1289]:CGContextAddPath:无效上下文

10 月 25 日星期日 15:12:14 jasonsmacbook TestProject[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 方法中设置属性感到困惑。对于哪种方式最好,似乎没有共识。

4

10 回答 10

84

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

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

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

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

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

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

于 2009-10-25T21:15:46.307 回答
17

关于你的阵列。线

NSMutableArray *array = [NSMutableArray array];

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

这是基本规则:

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

于 2009-10-25T23:04:09.353 回答
10

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

于 2011-11-10T12:37:08.040 回答
7

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

请注意,此类错误通常发生在autoreleased对象中,这意味着问题的最终原因不会在触发的调用堆栈中EXC_BAD_ACCESS。那是 NSZombieEnabled 和 NSAutoreleaseFreedObjectCheckEnabled 变得有用的时候。

于 2009-10-25T23:01:37.947 回答
5

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

于 2011-11-15T11:24:54.520 回答
2

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

于 2009-10-25T22:23:46.637 回答
2

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

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

来自:http ://blog.emmerinc.be/index.php/2009/03/19/break-on-exception-in-xcode/

于 2010-05-23T04:39:14.260 回答
1

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

NSDictionary *dic = [NSDictionary dictionaryWithObjectsAndKeys: myObj1, @"goodKey", myObj2, "badkey @ is missing in front", nil];
于 2011-08-13T11:59:07.257 回答
1

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

收到更详细的错误消息会很好,但我想这是它起源的框架的责任......无论如何,这是一个相当常见的搜索着陆,也许这会帮助一些人犯错正如我发现自己。

于 2016-09-23T06:29:03.123 回答
0

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

于 2014-03-26T16:55:21.557 回答