打破XCode中的EXC_BAD_ACCESS?
-
06-07-2019 - |
题
我不熟悉iPhone开发和XCode,也不知道如何开始对 EXC_BAD_ACCESS
信号进行故障排除。如何让XCode在导致错误的确切行中断?
我似乎无法让XCode停在线上导致问题,但我确实在调试控制台中看到以下几行:
Sun Oct 25 15:12:14 jasonsmacbook 测试项目[1289]: CGContextSetStrokeColorWithColor: 无效的上下文
Sun Oct 25 15:12:14 jasonsmacbook 测试项目[1289]: CGContextSetLineWidth:无效的上下文
Sun Oct 25 15:12:14 jasonsmacbook 测试项目[1289]: CGContextAddPath:无效的上下文
Sun Oct 25 15:12:14 jasonsmacbook 测试项目[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方法中设置属性。关于哪种方式最好,似乎没有达成共识。
解决方案
对于任何EXC_BAD_ACCESS错误,您通常会尝试向已发布的对象发送消息。 BEST 跟踪这些内容的方法是使用 NSZombieEnabled 。
这可以通过从不实际释放对象来实现,而是通过将其包裹为“僵尸”来实现。并在其中设置一个标志,表示它通常会被释放。这样,如果您再次尝试访问它,它仍然知道在发生错误之前它是什么,并且通过这些信息,您通常可以回溯以查看问题所在。
当调试器有时会抓取任何有用的信息时,它特别有助于后台线程。
非常重要但是,您需要100%确保这只是在您的调试代码而不是您的分发代码中。因为什么都没有发布,你的应用程序将泄漏,泄漏和泄漏。为了提醒我这样做,我把这个日志放在我的appdelegate:
if(getenv("NSZombieEnabled") || getenv("NSAutoreleaseFreedObjectCheckEnabled"))
NSLog(@"NSZombieEnabled/NSAutoreleaseFreedObjectCheckEnabled enabled!");
如果您需要帮助查找确切的行,请执行构建和调试( CMD-Y )而不是构建并运行( CMD-R )。当应用程序崩溃时,调试器会向您显示确切的行,并与NSZombieEnabled结合使用,您应该能够确切地找到原因。
其他提示
关于你的阵列。这条线
NSMutableArray *array = [NSMutableArray array];
实际上并没有给你一个保留的对象,而是一个自动释放对象。它可能会保留在下一行,但是你不应该在第三行中释放它。请参见此
这是基本规则:
如果使用名称以“ alloc”开头的方法创建对象,则取得对象的所有权。或“新”或包含“复制” (例如,alloc,newObject或mutableCopy),或者如果您向其发送保留消息。您有责任使用release或autorelease放弃您拥有的对象的所有权。在收到对象的任何其他时间,您都不能释放它。
在Xcode 4中,您可以通过单击Scheme下拉列表(左上角,停止按钮旁边)来启用Zombies - >编辑方案 - >诊断标签 - >启用Zombie Objects
Xcode / gdb总是在 EXC_BAD_ACCESS
上中断,你只需要在调用堆栈中找到触发它的代码。
请注意, autoreleased
对象经常会出现这类错误,这意味着问题的最终原因不在于触发 EXC_BAD_ACCESS
的调用堆栈中。那时NSZombieEnabled和NSAutoreleaseFreedObjectCheckEnabled变得有用了。
旧线程的新答案...在XCode 4中,诊断EXC_BAD_ACCESS异常的最有效方法是使用Instruments来分析您的应用程序(从XCode单击产品/配置文件并选择Zombies)。这将帮助您识别发送到解除分配对象的消息。
来自斯坦福CS193P类:如果你为符号 objc_exception_throw
添加一个断点(手动,通过编辑断点),你可以更好地了解出了什么问题 - 让事情继续下去调试器自行停止的地方往往会掩盖事物并搞砸堆栈跟踪。当您在objc_exception_throw中停止时,您通常可以回顾到导致问题的确切访问/操作。
另一种有用的方法是设置在发生异常后直接触发的断点:
打开断点窗口(Run– Show– Breakpoints)并添加两个名为“ objc_exception_throw”和[“ [NSException raise]"
来自: http://blog.emmerinc.be/index.php/2009/03/19/break-on-exception-in-xcode/
只是想为来自网络的其他人添加,为相同的错误搜索解决方案,但有不同的错误。在我的情况下,当我尝试使用键名中的拼写错误来实例化NSDictionary时我得到了同样的错误,我忘记添加“@”在我的钥匙前面:
NSDictionary *dic = [NSDictionary dictionaryWithObjectsAndKeys: myObj1, @"goodKey", myObj2, "badkey @ is missing in front", nil];
我希望我没有错过相同的答案,但我发现有些项目可能会因为运行在可能与项目依赖项或框架不兼容的旧iOS版本的模拟器上而抛出此错误。我正在追逐其中一个下来太长时间才意识到它刚刚发生在-older-模拟器版本中,比如iPhone 4S,该应用甚至不应该试图支持。
本来很高兴得到一个更详细的错误信息,但我想这是它起源的框架的责任......无论如何,这是一个相当常见的搜索着陆,也许这将有助于某人游玩和我发现的一样糟糕。
在启用僵尸之前,我建议先删除所有警告(如果有的话)。像没有 return
的非void函数这样的简单事情可能会导致此错误。如果您没有警告,请按照其他答案的建议继续进行。