歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> (iPhone/iPad)淺談Objective-C中release和nil的關系

(iPhone/iPad)淺談Objective-C中release和nil的關系

日期:2017/3/1 10:36:09   编辑:Linux編程

注意到經常有一個這樣的問題:某指針對象先release後=nil,這裡後跟個=nil有什麼作用?不寫行不行?

簡單一點說是,release是用來釋放內存,nil是將對象指針設為null,nil本身對內存沒什麼影響,但他處理指針,尤其是避免野指針倒是很有必要。

舉一個例子:

NSString *str=[[NSString alloc] init];

當我不需要str時

執行[str release];

str 的retain值減1,但是如果當前retain值>0,卻緊隨其後加一句str=nil;那麼這時[str retainCount]應該為0,因為[nil retainCount]==0;但這時很明顯存在內存洩露。

所以一個很好的寫作習慣是:

當對象的retainCount==1時,寫完[str release];後接著寫上str=nil; 這樣,當在後面的代碼再次調用str相關的方法屬性,也不會報錯,因為之前已經將str設置為空指針,再調用str的方法也會被認為是null,不會真正調用,更不會報錯。

例如下列代碼:(以下所有代碼段都已經過實際操作驗證)

[cpp]
  1. UIView *view1=[[UIView alloc] init];
  2. UIView *view2=[view1 retain];
  3. int i=[view1 retainCount];
  4. NSLog(@"i:%d",i);
  5. [view1 release];
  6. view1=nil;
  7. [view1 addSubview:view2];
整個程序運行,是不會crash的。但是存在內存洩露。

但是,現在又有另外一個問題,請看下列代碼:

[cpp]
  1. UIView *view1=[[UIView alloc] init];
  2. UIView *view2=[view1 retain];
  3. int i=[view1 retainCount];
  4. NSLog(@"i:%d",i);
  5. [view1 release];
  6. view1=nil;
  7. [view1 addSubview:view2];
  8. i=[view1 retainCount];
  9. NSLog(@"i:%d",i);
  10. i=[view2 retainCount];
  11. NSLog(@"i:%d",i);
  12. [view2 release];
  13. i=[view2 retainCount];
  14. NSLog(@"i:%d",i);
請問終端輸出的log應該是什麼?

第一個i=2,沒問題,因為view1 init了一次,retain了1次,retain值為2。

第二個i=0,根據上面所講的推斷,也沒問題,因為之前view1=nil,空指針的retainCount值為0。

第三個i=1,也沒什麼問題,因為view2是一個被賦了值的新指針,它不同於指針view1,二者是2個獨立的指針,而且,view2還被賦了值分配了內存地址。

但是,第四個i呢?i=?

答案是i=1。為什麼會這樣?下面是真實輸出結果:

[cpp]
  1. 2011-12-09 01:17:07.364 ReleaseNildemo[19115:f803] i:2
  2. 2011-12-09 01:17:07.365 ReleaseNildemo[19115:f803] i:0
  3. 2011-12-09 01:17:07.366 ReleaseNildemo[19115:f803] i:1
  4. 2011-12-09 01:17:07.367 ReleaseNildemo[19115:f803] i:1
為什麼會這樣?按推理說,程序執行到輸出這句應該crash才對,我運行了好幾遍,確實沒有出現。晚上在網上和其他程序員討論這個問題,有人運行的情況是“有時候會crash,有時候不會。斷點的話不會crash”,最後大家討論的話題開始變成“系統是先輸出還是先回收?”,更有甚者,有人輸出了一下內存地址,發現是view2 release前後輸出的是同一個內存地址,說明,這個東西內存雖然釋放了,但是系統還沒來得及回收。

有時候crash,原因是你向一塊未申請的內存發送了一條消息,最終成了系統回收速度問題了,所以,個人認為,以後碰到類似這種問題,干脆手動init,release,至少這樣能很快釋放,更便於清楚當前對象的內存情況。

以上是我對release nil操作的一些理解,歡迎更多人加入討論中。

Copyright © Linux教程網 All Rights Reserved