代码之家  ›  专栏  ›  技术社区  ›  Eli

使用“obj!”时不允许在iPhone上访问。=零

  •  1
  • Eli  · 技术社区  · 15 年前

    我在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];
    

    所以我猜,因为自动释放池还没有释放,所以对象不是零,但它的保留计数是0,所以无论如何都不允许访问它…还是沿着这些线?

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

    编辑:我用两种方法解决了这个问题。首先,我不允许在这个边缘案例中选择实体。其次,我将它改为:

    //Deselect it if it has been selected.
    if (entity == selectedEntity)
    {
        selectedEntity = nil;
    }
    
    [entities removeObjectAtIndex:i];
    

    正如jib建议的那样,确保在释放变量的同时给它赋值为nil。

    5 回复  |  直到 15 年前
        1
  •  6
  •   unknown    15 年前

    如果一个对象(SelectedEntity)已被释放并释放,则它不等于零。它是指向任意内存块的指针,并将其延迟(如果(selectedentity!)=nil)是编程错误(exc_bad_access)。

    因此,常见的OBJ-C范式:

    [选择内容发布]; selectedEntity=零;

        2
  •  9
  •   bbum    15 年前

    这与短路无关。Objective-C将消息吃到nil,因此检查 selectedEntity != nil 不需要(因为发送到nil的消息对于bool返回类型将返回no)。

    exc_bad_访问不是可捕获的异常。这是一个灾难性的失败,通常是由于尝试跟随无效的指针而导致的。

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

    打开nszombies并重试。

    如果您的应用程序是线程化的,您是否正确地在线程之间同步SelectedEntity(请记住,一般来说,不支持从辅助线程中篡改UI)?


    您的文章已被编辑,以表明修复是:

    //Deselect it if it has been selected.
    if (entity == selectedEntity)
    {
        selectedEntity = nil;
    }
    
    [entities removeObjectAtIndex:i];
    

    这解决了这个问题,因为nsmutableArray将在删除时释放对象。如果保留计数为零,则对象将被解除分配,然后SelectedEntity将指向一个解除分配的对象。

        3
  •  0
  •   Nir Levy    15 年前

    我刚读过这个 http://developer.apple.com/mac/library/qa/qa2004/qa1367.html 这表明您得到的错误是由于过度释放对象造成的。这意味着尽管selectedentity是nill,但您已经多次发布了它,而且它不再是您的了。

        4
  •  0
  •   Marcus S. Zarra    15 年前

    在objc_exception_throw上放置一个断点,并查看它真正被抛出的位置。这条线不应该单独抛出一个exc-bad-u访问。

    您是否在if块中做了可能导致异常的事情?

        5
  •  0
  •   Russell Zornes    15 年前
     
    
    selectedEntity = obj;
    NSAutoreleasePool *pool = ...;
    [obj release];
    if (selectedEntity != nil && etc...) {}
    [pool release];
    
     

    你这里有一个悬空的指针或僵尸。selectedEntity指向的是obj,它在引用selectedEntity之前就被释放。这使selectedEntity非nil,但它是一个无效对象,因此对它的任何取消引用都将崩溃。

    你想重新发布obj而不是释放它。