使用“obj!= nil时,iPhone上的EXC_BAD_ACCESS

时间:2009-08-31 19:37:32

标签: iphone objective-c pointers exc-bad-access short-circuiting

我在Objective-C中有一行非常简单的代码:

if ((selectedEntity != nil) && [selectedEntity isKindOfClass:[MobileEntity class]])

偶尔我无法分辨,游戏在EXC-BAD-ACCESS的这行代码上崩溃了。它通常似乎是从游戏领域中删除某些内容的时间,因此我猜测所选择的实体被取消分配,然后这会产生。除了不可能选择现有的实体(但是谁知道,也许这在我的代码中实际上并不正确......),我特意检查是否 之前是一个selectedEntity的事实我访问它意味着我不应该在这里遇到任何问题。 Objective-C应该支持布尔短约束,但似乎不是编辑:看起来像短路与问题无关。

另外,我把@ try / @ catch放在这个代码块周围,因为我知道它偶尔会爆炸,但是这似乎被忽略了(我猜测EXC-BAD-ACCESS无法捕获)。

所以基本上我想知道是否有人知道我可以抓住这个并把它抛出的方式(因为我不关心这个错误,只要它不会让游戏崩溃)或者可以解释为什么它可能会发生。我知道Objective-C使用“nil”值做了奇怪的事情,所以我猜它指的是一些奇怪的空间既不是对象指针也不是nil。

编辑:只是为了澄清,我知道下面的代码是错误的,这是我猜测在我的程序中发生的事情。我问这是否会导致问题 - 确实如此。 : - )

编辑:看起来有一个边缘情况允许您在删除之前选择一个实体。所以,似乎代码的进展如下:

selectedEntity = obj;
NSAutoreleasePool *pool = ...;
[obj release];
if (selectedEntity != nil && etc...) {}
[pool release];

所以我猜测因为Autorelease池还没有被释放,所以对象不是nil但是它的保留计数为0所以不允许它被访问...或者沿着那些行?

另外,我的游戏是单线程的,所以这不是一个线程问题。

编辑:我以两种方式解决了问题。首先,我不允许在该边缘案例中选择实体。其次,不是只调用[entities removeObjectAtIndex:i](删除任何将被删除的实体的代码),而是将其更改为:

//Deselect it if it has been selected.
if (entity == selectedEntity)
{
    selectedEntity = nil;
}

[entities removeObjectAtIndex:i];

请确保在释放变量的同时为变量分配nil,正如jib建议的那样。

5 个答案:

答案 0 :(得分:9)

这与短路无关。 Objective-C将消息写为nil,因此不需要检查selectedEntity != nil(因为对于BOOL返回类型,messages-to-nil将返回NO。)

EXC_BAD_ACCESS不是可捕捉的例外。这是一个灾难性的失败,通常是由于试图跟随无效指针造成的。

更有可能的是,在执行代码之前已经释放了selectedEntity指向的任何对象。因此,它既不是零也不是有效的对象。

启用NSZombies并重试。

如果您的应用程序是线程化的,您是否正确地跨线程同步selectedEntity(请记住,一般来说,不支持从辅助线程进行UI操作)?


您的帖子已经过编辑,表明该修复程序为:

//Deselect it if it has been selected.
if (entity == selectedEntity)
{
    selectedEntity = nil;
}

[entities removeObjectAtIndex:i];

这解决了这个问题,因为NSMutableArray会在删除时释放对象。如果保留计数降为零,则取消分配对象,然后selectedEntity将指向释放的对象。

答案 1 :(得分:6)

如果一个对象(selectedEntity)已被释放并且dealloc'd它不是== nil。它是指向任意内存的指针,并引用它(if(selectedEntity!= nil)是编程错误(EXC_BAD_ACCESS)。

因此,常见的obj-c范例: -

[selectedEntity release]; selectedEntity = nil;

答案 2 :(得分:0)

我刚读过这个http://developer.apple.com/mac/library/qa/qa2004/qa1367.html,表示你得到的错误是过度释放对象的结果。这意味着altough selectedEntity是nill,你发布了很多次,它不再是你的使用了..

答案 3 :(得分:0)

在OBJC_EXCEPTION_THROW上放置一个断点,看看它实际被抛出的位置。该行不应该自己抛出EXC_BAD_ACCESS。

你是否可能在IF块中做一些可能导致异常的事情?

答案 4 :(得分:0)

 

selectedEntity = obj;
NSAutoreleasePool *pool = ...;
[obj release];
if (selectedEntity != nil && etc...) {}
[pool release];

 

你这里有一个悬垂的指针或僵尸。 selectedEntity指向obj,它在您引用selectedEntity之前获取版本。这使得selectedEntity非nil但是一个无效的对象,因此任何取消引用它都会崩溃。

你想自动释放obj而不是释放它。