打破XCode中的EXC_BAD_ACCESS?

jas*_*onh 45 iphone debugging xcode exc-bad-access objective-c

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


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

Sun Oct 25 15:12:14 jasonsmacbook TestProject [1289]:CGContextSetStrokeColorWithColor:无效的上下文

Sun Oct 25 15:12:14 jasonsmacbook TestProject [1289]:CGContextSetLineWidth:无效的上下文

Sun Oct 25 15:12:14 jasonsmacbook TestProject [1289]:CGContextAddPath:无效的上下文

Sun Oct 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;    
}
Run Code Online (Sandbox Code Playgroud)

我删除了[array release]线,它不再给我EXC_BAD_ACCESS信号,但我现在很困惑为什么这个工作.我认为当我使用该属性时,它会自动为我保留它,因此我应该从内部释放它init以便我没有泄漏.我完全混淆了它是如何工作的,我读过的所有指南和Stackoverflow问题只会让我更加困惑如何在我的init方法中设置属性.关于哪种方式最好,似乎没有达成共识.

con*_*are 84

对于任何EXC_BAD_ACCESS错误,您通常会尝试向已发布的对象发送消息.跟踪这些问题的最佳方法是使用NSZombieEnabled.

这实际上是从不实际释放一个对象,而是通过将其包装为"僵尸"并在其中设置一个标志,表示它通常会被释放.这样,如果你再次尝试访问它,它仍然知道在你犯错之前它是什么,并且通过这些信息,你通常可以回溯看看问题是什么.

当调试器有时会破解任何有用的信息时,它特别有助于后台线程.

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

if(getenv("NSZombieEnabled") || getenv("NSAutoreleaseFreedObjectCheckEnabled"))
  NSLog(@"NSZombieEnabled/NSAutoreleaseFreedObjectCheckEnabled enabled!");
Run Code Online (Sandbox Code Playgroud)

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


epa*_*tel 17

关于你的阵列.这条线

NSMutableArray *array = [NSMutableArray array];
Run Code Online (Sandbox Code Playgroud)

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

这是基本规则:

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

  • @jasonh,两者都是.按照惯例,类似的类方法基本上是`alloc`和`init`的连接.但是返回的对象是自动释放的,因此您需要保留结果(实际上,要从分配它的类中声明它的所有权). (4认同)
  • 那么,基本上[[NSMutableArray array] retain]是一种方便的方法,不必输入[[NSMutable alloc] init]?;) (3认同)

sne*_*nez 10

在Xcode 4中,您可以通过单击Scheme下拉列表(左上角,停止按钮旁边) - > Edit Scheme - > Diagnostics选项卡 - >启用Zombie对象来启用Zombies


Dar*_*ren 7

Xcode/gdb总是打破EXC_BAD_ACCESS,你只需要在调用堆栈中找到触发它的代码.

请注意,autoreleased对象经常会出现这些类型的错误,这意味着问题的最终原因不会出现在触发的调用堆栈中EXC_BAD_ACCESS.那时NSZombieEnabled和NSAutoreleaseFreedObjectCheckEnabled变得有用了.


Jon*_*att 5

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