1

方法removeFromSuperView如何工作? 我的記憶問題不好訪問時,我想重新初始化視圖內存管理

- (id)init { 
    if (!(self = [super init])) 
     return nil; 

    _mainView = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 
    NSLog(@"retainCount :%d", [_mainView retainCount]); 
    UIButton *reInitButton = [[UIButton alloc] initWithFrame:CGRectMake(0.0f,0.0f,90.0f,35.0f)];  
    [reInitButton addTarget:self action:@selector(buttonDidTapped:) forControlEvents:UIControlEventTouchUpInside]; 
    [[self view] addSubView:_mainView]; 
    NSLog(@"retainCount :%d", [_mainView retainCount]); 
    [_mainView release]; 
    NSLog(@"retainCount :%d", [_mainView retainCount]); 

    return self; 
} 

- (void)buttonDidTapped:(id)sender { 
    [_mainView removeFromSuperView]; //crash during second times press the button 
    NSLog(@"retainCount :%d", [_mainView retainCount]); 
    _mainView = [[UIView alloc] initWithFrame[[UIScreen mainScreen] bounds]]; 
    [[self view] addSubView:_mainView]; 
    NSLog(@"retainCount :%d", [_mainView retainCount]); 
    [_mainView release]; 
    NSLog(@"retainCount :%d", [_mainView retainCount]); 
} 

我的NSLog每一個時代有任何保留或頁頭或釋放關鍵字。結果非常奇怪。

//init 
retainCount : 1 
retainCount : 2 
retainCount : 1 
//1st time pressed button 
retainCount : 1 //remove super view didn't decrease 
retainCount : 2 
retainCount : 1 
//2nd time pressed button 
retainCount : 0 //crash. Memory bad access 

奇怪的是它爲什麼沒有在第一次按下時崩潰?

回答

3

我覺得你的問題是在這裏:

[_mainView release]; 

您已經降到大家參考_mainView,然而,以我的閱讀,這是一個成員變量,你會保持周圍,並繼續在調用方法。這是無效的。一旦你調用了-release,你基本上已經告訴系統你不會再使用該對象,並且不能對指向該對象的陳舊指針做任何有用的操作,就像你在調用-removeFromSuperView時做的那樣之後。

如果你想繼續保留_mainView並在其上調用代碼,你需要保留一個參考。也許你應該將發佈版本移到你的對象的-dealloc方法中。或者,您可以在按鈕方法中使用-release,並在下次需要時重新創建新視圖。

作爲一個有用的提示,很多程序員喜歡在釋放它們之後將對象重置爲NULL(或objC-speak中的nil),以提醒您不能再次使用該對象。如果你-release的東西,你最好是這個意思。

最後,我建議你谷歌術語「引用計數」,並閱讀它;這是一個比NSObject更具通用性的成語,它可能會幫助您思考基本知識,以及如何用另一種語言(如C,C)來實現此功能。這有助於您更好地理解引用計數對象。

+0

+1在這種情況下設置爲零。 – 2011-05-15 05:33:51

+0

請注意,將release釋放到'dealloc',並且仍然在按鈕的動作中創建新視圖將導致泄漏。 – 2011-05-15 05:42:45

+0

@Josh Caswell - 是的,的確如此。這是'nil'事情派上用場的地方...... if(_mainView)[_mainView release]; _mainView =/* ... * /;'但是你仍然希望在dealloc中有一個版本。 – asveikau 2011-05-15 05:45:33

3

永遠不要使用RETAINCOUNT。對不起,把它放在帽子裏,但我無法弄清楚爲什麼人們仍在使用它。這是內存管理的一個錯誤參考。使用儀器或類似的東西。

+0

ok我不會再使用它了,它有什麼問題,我想我已經發布了它的需要,但它仍然崩潰。如果我在buttonDidTapped中註釋了這個版本:它沒有崩潰,但我認爲它被泄露 – Lunayo 2011-05-15 05:18:30

+0

觀察引用計數(這是一個比「retain count」更標準的術語,所以也許google瞭解它)在'-retain'或'-release'等特定方法的實現之外。問題是如果refcount爲零,則支持該對象的內存(包括支持refcount本身的內存)被釋放,因此在放棄引用後訪問對象是不安全的,出於同樣的原因,您無法觸及'free'後的緩衝區。其他代碼片段也可以保留並釋放內存,並且你不能依賴他們的行爲。 – asveikau 2011-05-15 05:23:41

+0

@Lunayo:[retainCount認爲有害](http://stackoverflow.com/questions/5784084/)關於該主題的其他有趣的解讀:[1](http://stackoverflow.com/questions/5155559/)[2] (http://stackoverflow.com/questions/5483357/)[3](http://stackoverflow.com/questions/5391479/)[4](http://stackoverflow.com/questions/3354724/)[5 ](http://stackoverflow.com/questions/5220902/) – 2011-05-15 05:25:40

2

此時您不應該訪問_mainView。這可能很難解釋,請耐心等待。我們將計算,但不是絕對保留數,只是您的代碼對該對象的聲明。

你爲一個對象,並在點其分配存儲器與_mainView

_mainView = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 

您有1個如權利要求所有權的到該對象。當你將它作爲另一個視圖的子視圖添加時,該視圖同樣會聲明所有權,但那不是你的,而是視圖的。它使_mainView中的對象繼續存在的事實是一個意外,你不應該依賴它。然後你釋放對象:

[_mainView release]; 

你已經放棄自己的所有權聲明 - 你現在有0索賠,你不再嘗試訪問該對象。你不擁有它。同樣,由於另一種觀點正在使用它,以及你仍然有一個指向它的事實,它仍然存在的事實是事故*,你不應該依賴它們。

當談到時間來處理你按下按鈕,那麼,你所訪問過,你有沒有所有權的對象:

[_mainView removeFromSuperView]; 

,這會導致系統崩潰,這可能無法預料,但它是不無道理。通過讓你的所有權聲明變爲0,你告訴系統「我不再需要這個對象,在這之後我不會再訪問它,如果它消失了,我不會受到影響。」實際上,雖然,你需要需要它留下來,你需要訪問它。

你應該做的,那麼,是招行:

[_mainView release]; 

的按鈕動作裏面,調用removeFromSuperview之後。


*其中的第二個可以通過設置_mainView = nil;你釋放後,在這種情況下是可以避免的,但不會解決更大的問題。