[英]Memory Management
方法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
奇怪的是為什么它在第一次按下時沒有崩潰?
切勿使用RETAINCOUNT 。 很抱歉將其設置為大寫,但我無法弄清楚為什么人們仍然使用它。 這是內存管理的錯誤參考。 請改用樂器或類似工具。
我認為您的問題在這里:
[_mainView release];
您已經刪除了對_mainView
的引用,但是,根據我的閱讀,這是一個成員變量,您將保留它並繼續調用方法。 那是無效的。 調用-release
,您實際上已經告訴系統不再使用該對象,並且對於指向該對象的陳舊指針,您將無法做任何有用的事情,就像調用-removeFromSuperView
時-removeFromSuperView
稍后。
如果要繼續保留_mainView
並在其上調用代碼,則需要保留引用。 也許您應該將發行版移至對象的-dealloc
方法。 或者,您可以在按鈕方法中-release
它,並在下次需要時重新創建一個新視圖。
作為一個有用的技巧,許多程序員喜歡在釋放對象后將對象重置為NULL
(或者在objC語言中為nil
),以提醒您不能再次使用該對象。 如果您-release
某物,則最好做到這一點。
最后,我建議您使用Google的“引用計數”一詞,並仔細閱讀; 與NSObject
的細節相比,它是一個更通用的習慣用法,考慮基礎知識以及如何用另一種語言(例如C)實現這一點很有用。這將幫助您更好地推理引用計數對象。
_mainView
您不應該訪問_mainView
。 這可能很難解釋,所以請忍受。 我們要計算的不是對象的絕對保留數,而是絕對保留數。
您為對象分配內存,並使用_mainView
指向該對象:
_mainView = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
您對該對象有1個所有權聲明。 當您將其添加為另一個視圖的子視圖時,該視圖同樣會聲明所有權,但這不是您的,而是視圖的所有權。 它使_mainView
的對象粘住的事實是偶然的,因此您不應該依賴它。 然后釋放對象:
[_mainView release];
您已放棄所有權聲明-您現在擁有0個聲明,並且您不應再嘗試訪問此對象。 你不擁有它。 同樣,由於另一個視圖正在使用它而仍然存在它的事實,以及您仍然有指向它的指針的事實是偶然事件*,您不應依賴它們。
是時候處理按鈕按下了,您正在訪問一個沒有所有權的對象:
[_mainView removeFromSuperView];
這會導致崩潰,這是無法預料的,但這並非不合理。 通過將您的所有權聲明設為0,您告訴系統“我不再需要該對象。在此之后,我將不再訪問它。如果它消失了,我將不會受到影響。” 但是,實際上,您確實需要它保持存在,並且需要訪問它。
然后,您應該做的是移動這行:
[_mainView release];
到按鈕動作內部, removeFromSuperview
在調用removeFromSuperview
。
*通過設置_mainView = nil;
可以避免第二種情況_mainView = nil;
在這種情況下,將其釋放后,就無法解決更大的問題。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.