1

我有代碼的Objective-C中一個非常簡單的線條時:EXC_BAD_ACCESS在iPhone上使用「OBJ =零

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

有時無緣無故我可以告訴大家,遊戲崩潰在這條線代碼與EXC-BAD-ACCESS通常似乎是關於什麼時候某些東西從遊戲區域中刪除的時間,所以我猜想 selectedEntity會被解除分配,那麼結果就是這樣。不可能選擇退出的實體(但是誰知道,也許這在我的代碼中實際上並不是這樣)......我之前專門檢查是否有 selectedEntity訪問它意味着我不應該在這裏遇到任何問題。 Objective-C應該支持布爾短期引用,但它似乎不是EDIT:看起來像短路與問題無關。

另外,我在這個代碼塊中放了一個@ try/@ catch,因爲我知道它每隔一段時間就會爆炸一次,但這似乎被忽略了(我猜EXC-BAD-ACCESS不能抓住)。

所以基本上我想知道是否有人知道我可以抓住它並拋出它的方式(因爲只要它不會造成遊戲崩潰,我不在意這個錯誤),或者可以解釋爲什麼它可能正在發生。我知道Objective-C用「nil」值做奇怪的事情,所以我猜測它指向一個奇怪的空間,它既不是對象指針也不是零。

編輯:只是爲了澄清,我知道下面的代碼是錯誤的,這是我猜測發生在我的程序中。我在問,這是否會導致一個問題 - 的確如此。 :-)

編輯:看起來像有一個邊緣的情況下,可以讓你選擇一個實體之前,它被擦除。因此,它出現在代碼的進展是這樣的:

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

所以我猜測,因爲自動釋放池尚未公佈,對象不是零,但其保留計數爲0,所以它的無論如何不允許訪問......或者沿着這些路線的東西?

另外,我的遊戲是單線程的,所以這不是線程問題。

編輯:我解決了這個問題,有兩種方法。首先,我不允許選擇該邊緣案例中的實體。其次,而不只是調用[實體removeObjectAtIndex:I](代碼刪除將被刪除的任何實體),我把它改爲:

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

[entities removeObjectAtIndex:i]; 

只要確保你在分配零的變量就像jib建議的那樣,你同時釋放它。

+0

-removeObjectAtIndex:將遞減保留計數,如果它達到零,則釋放該對象。殭屍會檢測到這一點。因此,您在上次編輯中指定爲零可修復問題。 – bbum 2009-08-31 20:46:29

回答

6

如果一個對象(selectedEntity)已經被釋放並且被解除分配,它不是== nil。它是一個指向的存儲器的任意的片,和deferencing它(如果(selectedEntity =無)是一個編程錯誤(EXC_BAD_ACCESS)

因此,常見的obj-C範式: - 。

[selectedEntity釋放]; selectedEntity =零;

+0

這正是我需要知道的。非常感謝! – Eli 2009-08-31 20:13:06

+7

這是不正確的。 selectedEntity!= nil將**從不**導致EXC_BAD_ACCESS。 EXC_BAD_ACCESS只有在解引用指針時纔會發生,這會在消息發送時發生。 – bbum 2009-08-31 20:44:41

+1

是的,的確如此,你可以隨時檢查某些東西的值而不會導致錯誤,但是你不能通知它。 – Eli 2009-08-31 22:02:07

9

這與短路無關。 Objective-C消息爲零,因此不需要檢查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裏將在移除-release對象。如果保留計數降至零,則對象將被解除分配,然後,selectedEntity將指向一個已解除分配的對象。

+0

你認爲我指出了正確的方向。你能看看我的編輯對你有意義嗎? – Eli 2009-08-31 19:58:51

0

我剛剛讀了這個http://developer.apple.com/mac/library/qa/qa2004/qa1367.html這表明你得到的錯誤是過度釋放對象的結果。這意味着選擇的實體很糟糕,你將它釋放了很多次,它不再是你的使用了。

+0

它並不總是一個過度釋放的問題,並不是在這種情況下(我從來沒有調用釋放或保留在對象上,它只是添加到NSMutableArray中,然後從中移除)。 – Eli 2009-08-31 20:01:19

0

在OBJC_EXCEPTION_THROW上放置一個斷點,看看它在哪裏真的被拋出。該行不應該自行拋出EXC_BAD_ACCESS。

你可能正在做一些可能導致異常的IF塊嗎?

0


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

你有一個懸擺指針或殭屍這裏的selectedEntity在OBJ這對你參考selectedEntity之前得到釋放指着這使得selectedEntity非空,但一個無效的對象,因此任何。它的解除引用將會崩潰。

你想autorelease obj而不是釋放它。

+0

我應該更清楚 - 我知道上面的代碼是一個問題,這是我懷疑發生的一個非常簡化的版本。我並不是問這是否是正確的代碼。 :-) – Eli 2009-08-31 20:20:15