關于IOS開發的內存管理的文章已經很多了,因此系統的知識點就不寫了,這里我寫點平時工作遇到的疑問以及解答做個總結吧,相信也會有人遇到相同的疑問呢,歡迎學習IOS的朋友請加ios技術交流群:190956763,共同學習,共同進步!
假如在.h文件里,定義一個變量@property (nonatomic,retain) AController *aController;
疑問1:創建對象時候,一般會使用alloc,new,copy或者mutalbeCopy等方法,
哪種寫法是正確的?
A self.aController=[[AController alloc] init];
B self.aController=[[[AController alloc] init] retain];
C self.aController=[[[AController alloc] init] autorelease];
D self->aController=[[AController alloc] init];
答案:C,D 引用計數的主要接口alloc,allocwithzone,new(帶初始化) 為對象分配內存,retainCount為“1”,并返回此實例,而調用self.aController,self本身有干了活,他把_aController這個變量相當于又retain一下,因此A的retaincount已經是2了,已經泄露了!因此不需要B這樣retain了,加autorelease的話,就會把剛才新建那塊內存自動釋放掉的,如果用D話,沒有執行aController的setter方法,因為此時retainCount為“1”,所以D也是正確的,C的話也能用,但是不是好的用法
疑問2:在dealloc方法中,這么寫有問題嗎?
- (void)dealloc{ [self.aController release]; self.aController = nil; [super dealloc]; }
答案:這里不需要release了,因為self.aController = nil;已經調用了release了,當然也可以這么寫
- (void)dealloc{ [self->aController release]; self->aController = nil; [super dealloc]; }
解釋:對于set method來說,用synthesize來讓系統幫我們生成的set方法和如下的類似:
- (void)setAbc:(id)newAbc { if(_abc != newAbc){ [_abc release]; _abc = [newAbc retain]; //是retain還是copy取決于你property聲明時的attributes } }
如果新值和成員相等,就不需要進行重復的賦值了,不等的話,需要把新值賦給成員,同時,成員_abc原來的內容就不需要了,這里要先調用release進行釋放。(這個具體的原因在那本講Objective-C的書中寫的很清楚,請查看)。
因此在這里,調用self.abc = nil;
就等于已經調用了[_abc release]; 和_abc = nil;
self.abc = nil;和[_abc release]; 都不一定釋放對象,因為該對象還可能被別的引用,這里的操作的意圖就是:別的地方用沒用_abc我不知道,在這里的_abc我不用了。
為什么release后還要設置nil呢?因為是這樣的,如果引用 計數等于0還對該對象進行操作,則會出現內存訪問失敗,crash,所以盡量設置為nil,但是單純設置為nil,如果retaincount不是0的話,內存一樣泄露的,因此應該設置nil的時候,先保證變量的retaincount是0了
疑問3:為什么有些變量不用考慮retain,release呢?
NSString *str1 = @”constant string”;
str1的retain count是個很大的數字。Objective-C對常量字符串做了特殊處理。
當然,如果你這樣創建NSString,得到的retain count依然為1
NSString *str2 = [NSString stringWithFormat:@”123”];
但實際上對于 [NSString stringWithFormat:] 這類構造函數返回的對象都是autorelease的,所以也不用考慮retain,release
疑問4:在ARC的情況下,按說不用自己在考慮release了,為什么還會有dealloc方法存在呢?
答案:雖然在ARC下,不用考慮release了,但是我們可能還要釋放一些其他的東西,比如delegate,關閉定時器,關閉gps定位等,另外如果在ARC下,我們自己不放心,為了安全,自己釋放變量也沒有什么錯誤發生!另外不用再調用[super dealloc]了
比如在ARC下,我們可能會這么寫
- (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; [self.closeButtonTimer invalidate]; [self.webView setDelegate:nil]; [self setLocationDetectionEnabled:NO]; }
注意:比如Delegate,如果不在dealloc中釋放它,如果頁面有多線程的調用,比如開辟個線程從網上down圖片子類的,它down下來后需要找這個頁面,但是可能用戶操作比較快,比如點了后退按鈕,這時候頁面可能已經銷毀了,于是就導致頁面崩潰了,所以dealloc中要釋放掉delegate
疑問5:怎么能知道哪里內存泄露了呢?
這個就不詳細解釋了,看相關的帖子說的很詳細了
http://www.cocoachina.com/newbie/basic/2012/1204/5242.html
疑問6:聲明為IBOutlet屬性的,在MRC中應該retain還是assign?在ARC中應該是strong還是weak?
在MRC中,應該是retain的,因為IBOutlet本身就是retain的
任何一個被聲明為IBOutlet并且在Interface Builder里被連接到一個UI組件的成員變量,會被額外retain一次。
常見的情形如
IBOutlet UILabel *label; |
這個label在Interface Builder里被連接到一個UILabel。此時,這個label的retainCount為2。
所以,只要使用了IBOutlet變量,一定需要在dealloc或者viewDidUnload里release這個變量。
在ARC中,property,我們將其申明為weak(事實上,如果沒有特別意外,除了最頂層的IBOutlet意外,自己寫的outlet都應該是weak)。通過加載xib得到的用戶界面,在其從xib文件加載時,就已經是view hierarchy的一部分了,而view hierarchy中的指向都是strong的。因此outlet所指向的UI對象不應當再被hold一次了。將這些outlet寫為weak的最顯而易見的好處是你就不用再viewDidUnload方法中再將這些outlet設為nil了(否則就算view被摧毀了,但是由于這些UI對象還在被outlet指針指向而無法釋放)。
參考:
http://www.16kan.com/post/214006.html
http://www.ityran.com/archives/1234
疑問7:在ARC在,如果用retain,和用strong有什么區別?
retain關鍵字在ARC中是依舊可用的,它在ARC中所扮演的角色和strong完全一樣。為了避免迷惑,最好在需要的時候將其寫為strong,那樣更符合ARC的規則。
文章列表