2011-06-26 90 views
2

Resold!被稱爲兩次的Dealloc?

感謝Lone Gunman,這個問題是由於在發佈它們之前沒有將許多代表設置爲零的疏忽。

這是一個奇怪的...我熟悉基本的內存管理,但我認爲我看到的東西是不尋常的。這裏是一個小背景...

我有一個NavigationController,處理以下ViewControllers之間導航:

首頁 - >遊戲 - >遊戲

運行代碼時離開時摔倒遊戲。內GameViewController有一個類似於dealloc方法:

- (void)dealloc 
{ 
    [board release]; 
    [opponentsViewController release]; 
    [instructionsViewController release]; 
    [imgPicker release]; 
    [gameView release]; 
    [super dealloc]; 
} 

當導航控制器返回到遊戲列表(從遊戲中),它拋出一個EXC_BAD_ACCESS。所以我提出了我可靠的剖析器並檢查殭屍。唉,就像我預料的那樣,一條消息正在發送到一個釋放對象!進一步挖掘我發現那裏是在對象的歷史記錄3項:

  1. 局取得alloc'd(通過遊戲的init方法調用)
  2. 局得到釋放(通過遊戲的dealloc方法調用)
  3. 局之中Zombie'd(由Game的dealloc方法調用)

這兩個調用2和3都是從UINavigationController setDisappearingViewController中調用的。

在我的dealloc方法中,我爲每個釋放調用設置了斷點,這時會發生[board release]調用,然後發生[opponentsViewController release]調用,然後再次發生[board release]調用。所以我看到dealloc方法沒有完成並再次調用。

什麼可能導致這種情況?

編輯:這是GameViewController Implementation

從遊戲控制器代碼,增加了本場比賽:

-(void) gotoGame:(int)tag { 

    game = [[GameViewController alloc] init]; 
    [self.navigationController pushViewController:game animated:YES]; 
    [game release]; 

} 

編輯:這是GameViewController Header

+0

' - [NSObject dealloc]'不能執行兩次。如果您在構建設置中啓用「運行靜態分析器」並嘗試再次構建,您會遇到什麼問題? – 2011-06-26 16:01:25

+0

當您多次調用發佈時會發生這種情況。你能檢查你沒有在程序的其他任何地方發佈主板嗎?> – sumderungHAY

+0

@ WTP:沒有來自靜態分析器的投訴。 – Brent

回答

3

我會嘗試所有的伊娃的代表設置爲零(編輯:在的dealloc)的init方法。我有一個類似的問題與獲取結果控制器。無法在dealloc中將其委託設置爲零,並且核心數據堆棧在視圖控制器發佈時仍有指向它的指針。

所以,這是我的賭注,設置伊娃代表在dealloc中爲零,但我看不到您的標題,以瞭解您遵守的協議是什麼。

編輯:解釋

設置一個委託實際上是給在執行該代表團的指針(我相信它通常是一個分配的屬性)的對象。

@property (assign) delegate; 

我將使用我作爲示例的問題。

假設你有一個視圖控制器,它有一個fetchedResultsController作爲ivar。當您設置FRC代理時:

fetchedResultsController.delegate = self; 

並且視圖控制器被釋放,任何使用該指針的對象仍然認爲它是活的。你會想,既然FRC也是在dealloc中發佈的,那麼你會沒事的(這就是爲什麼我花了4天時間才弄清楚:)),但是有時候實現的其他部分也會使用你的委託。所以修復是:

-(void)dealloc 
{ 
    self.fetchedResultsController.delegate = nil; 
    [_fetchedResultsController release]; 
    [super dealloc]; 
} 

注意:只要新工具可用於所有人,您將不必擔心這個東西了^^;

+1

這真是一個很好的觀點。這裏是標題,在這裏有一批代表團......我想這是正確的方向。 – Brent

+0

修正了,謝謝!我希望有人能幫助填補我的知識空白。代表們做了什麼讓dealloc看起來像兩次發射?他們的方法中的[super dealloc]調用是否會導致它再次觸發? – Brent

+0

我爲答案添加了一個解釋。 –

-3

嘗試

- (void) dealloc { 
    if(game != nil){ 
    //release here 
    [game release]; 
    } 
    [super dealloc]; 
    } 

通過看起來你已經在頭文件中聲明瞭遊戲的方式只是在推動你釋放它之後,並且還用dealloc方法釋放它。從dealloc方法中刪除釋放調用或者像這樣改變你的方法。

-(void) gotoGame:(int)tag { 

    GameViewController *game = [[GameViewController alloc] init]; 
    [self.navigationController pushViewController:game animated:YES]; 
    [game release]; 

} 

不使用標籤的任何地方

也會更新。你爲什麼不創建一個這樣

GameViewController *game = [[GameViewController alloc] initWithTag:tag]; 
[self.navigationController pushViewController:game animated:YES]; 
[game release]; 
+5

在發送釋放(或任何其他方法)之前,檢查是否有零是無用的。在nil上調用方法是一個noop。它什麼也沒做。因此你的建議也不會解決任何問題。 –

+0

@Johan Kool至少他的應用程序不會崩潰。 –

+3

你錯過了這一點。發送'-release'消息給'nil'將不會**他的應用程序崩潰。而且,一個對象在被釋放後不會自動成爲「nil」(換句話說,「nil」不表示垃圾值)。所以檢查是沒用的。 ('-dealloc'實現中通常做的一件事是將指針清零,這可以防止崩潰,但它也可以隱藏錯誤)。 –