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