Objective-C的記憶體管理(一)黃金法則的理解

來源:互聯網
上載者:User

標籤:

一、記憶體管理黃金法則:

The basic rule to apple is everything thatincreases the reference counter with alloc,[mutable]copy[WithZone:] or retainis in charge of the corresponding [auto]release.

如果一個對象使用了alloc,[mutable] copy,retain,那麼你必須使用相應的release或autonrelease

 

 

二、記憶體管理類型分類

基本類型和C語言的類型:如:

int,short,char,struct,enum,union等類型

OC類型:任何繼承於NSObject對象都屬於OC的類型。

我們講的記憶體管理實際上是對OC類型的記憶體管理,它對基礎資料型別 (Elementary Data Type)和C語言的類型並不管用。

 

 

三、C和C++記憶體管理的不足

 

如上,又3個引用指向了這一塊記憶體,任何一個調用了free方法釋放這個記憶體,而其餘的引用在不知道的情況下繼續使用這塊記憶體的時候,就會出現問題。何時由誰去釋放這塊記憶體,這就是C和C++在記憶體管理上的混亂。

 

 

四、OC對象在記憶體中的結構

所有的OC類型的對象的結構如下,這個對象的記憶體在包含自己的變數和方法的基礎上,還有一個包含retainCount的引用計數。

每一個OC對象都有一個4個位元組的retainCount的計數器。表示當前對象被引用的計數。如果計數為0,那麼就真正的去釋放這個對象。

 


 

規則:

1、Objective-C類中實現了引用計數器,對象知道自己當前被引用的次數

2、最初對象的計數器為1

3、如果需要引用對象,可以給對象發送一個retain訊息,這樣對象的計數器就加1

4、當不需要引用對象了,可以給對象發送release訊息,這樣對象計數器就減1

5、當計數器減到0,自動調用對象的dealloc函數,對象就會釋放記憶體

6、計數器為0的對象不能再使用release和其他方法

 

五、舉例說明

比如有一個引擎類Engine,有一個汽車類Car,Car裡面有一歌Engine的執行個體變數,一個setter和getter方法。具體如下

 

[plain] view plaincopy 
  1. #import "Car.h"  
  2.   
  3. @implementation Car  
  4.   
  5.   
  6. -(void)setEngine:(Engine*) engine  
  7. {  
  8.      _engine=engine;  
  9. }  
  10. -(Engine*)engine  
  11. {  
  12.     return _engine;  
  13. }  
  14.   
  15. -(void)dealloc  
  16. {  
  17.     NSLog(@"Car is dealloc");  
  18.     [super dealloc];  
  19. }  
  20. @end  



 

上面寫的是一個簡單的類,當讓這樣寫是有問題,所以需要一步步的改進。

第一步改進:

先使用它看問題的所在,在main方法裡面如下使用:

 

[plain] view plaincopy 
  1. //先建立一個引擎  
  2. Engine* engine1=[[Engine alloc]init];  
  3. [engine1 setID:1];  
  4. //在建立一個汽車,設定汽車的引擎  
  5. Car* car=[[Car alloc]init];//retainCount=1  
  6. [car setEngine:engine1];  
  7. /*分析:在這裡,現在有兩個引用指向這個Engine對象,engine1和Car中的_engine,可是這個Engine對象的引用計數還為1,因為在  
  8.  set方法中,並沒有使用retain。那麼不管是哪個引用調用release,那麼另外一個引用都會指向一塊釋放掉的記憶體,那麼肯定  
  9.  會發生錯誤。所以需要在set方法中加以改進。*/  


第二步改進:

 

setter方法改進

 

[plain] view plaincopy 
  1. -(void)setEngine:(Engine*) engine  
  2. {  
  3.      _engine=[engine retain];//多了一個引用,retainCount+1  
  4. }  

再在main中使用它

 

 

[plain] view plaincopy 
  1.  //先建立一個引擎  
  2.  Engine* engine1=[[Engine alloc]init];  
  3.  [engine1 setID:1];  
  4.  //在建立一個汽車,設定汽車的引擎  
  5.  Car* car=[[Car alloc]init];//retainCount=1  
  6.  [car setEngine:engine1];//retainCount=2,因為使用了retain,所以retainCount=2,  
  7.   
  8.  //假設還有一個引擎  
  9.  Engine* engine2=[[Engine alloc]init];  
  10.  [engine2 setID:2];  
  11.    
  12.  //這個汽車要換一個引擎,自然又要調用settr方法         
  13.   [car setEngine:engine2];  
  14.     
  15.  /*分析:在這裡,汽車換了一個引擎,那麼它的_engine就不在指向engine1的哪個對象的記憶體了,而是換成了engine2,也就是說engine1的哪個對象指向的記憶體的引用只有一個  
  16. 可是它的retainCount是兩個,這就是問題的所在了。所以仍然需要改進*/  


第三步改進:

 

 

[plain] view plaincopy 
  1. -(void)setEngine:(Engine*) engine  
  2. {  
  3.      [_engine release];//在設定之前,先release,那麼在設定的時候,就會自動將前面的一個引用release掉  
  4.     _engine=[engine retain];//多了一個引用,retainCount+1  
  5. }  

再在main‘中使用

 

 

[plain] view plaincopy 
  1. //先建立一個引擎  
  2. Engine* engine1=[[Engine alloc]init];  
  3. [engine1 setID:1];  
  4. //在建立一個汽車,設定汽車的引擎  
  5. Car* car=[[Car alloc]init];//retainCount=1  
  6. [car setEngine:engine1];//retainCount=2,因為使用了retain,所以retainCount=2,  
  7.   
  8. //如果進行了一個誤操作,又設定了一次engine1       
  9.  [car setEngine:engine1];  
  10.    
  11. /*分析:那麼,又要重新調用一次setter方法,這根本就是無意義的操作,浪費資源,所以要在設定之間加上判斷*/  


第四步改進:

 

 

[plain] view plaincopy 
  1. -(void)setEngine:(Engine*) engine  
  2. {  
  3.    if(_engine!=engine){//判斷是否重複設定  
  4.            [_engine release];//在設定之前,先release,那麼在設定的時候,就會自動將前面的一個引用release掉  
  5.            _engine=[engine retain];//多了一個引用,retainCount+1  
  6.       }  
  7.  }  


第五步:

 

現在setter方法基本沒有問題了,那麼在當我們要釋放掉一個car對象的時候,必須也要釋放它裡面的_engine的引用,所以,要重寫car的dealloc方法。

 

[plain] view plaincopy 
  1. -(void)dealloc  
  2. {  
  3.     [_engine release]; //在釋放car的時候,釋放掉它對engine的引用  
  4.     [super dealloc];  
  5. }  


這還不是最好的釋放的方法,下面的方法更好

 

 

[plain] view plaincopy 
  1. -(void)dealloc  
  2. {  
  3.     [_engine setEngine:nil]; //在釋放car的時候,對setEngine設定為nil,它不僅會release掉,並且指向nil,即使誤操作調用也不會出錯。  
  4.     [super dealloc];  
  5. }  



 

所以,綜上所述,在setter方法中的最終寫法是

 

[plain] view plaincopy 
  1. <span style="color:#CC66CC;">-(void)setEngine:(Engine*) engine  
  2. {  
  3.    if(_engine!=engine){//判斷是否重複設定  
  4.            [_engine release];//在設定之前,先release,那麼在設定的時候,就會自動將前面的一個引用release掉  
  5.            _engine=[engine retain];//多了一個引用,retainCount+1  
  6.       }  
  7.  }</span>  


然後在dealloc方法中寫法是:

 

 

[plain] view plaincopy 
  1. <span style="color:#CC66CC;">-(void)dealloc  
  2. {  
  3.     [_engine setEngine:nil]; //在釋放car的時候,對setEngine設定為nil,它不僅會release掉,並且指向nil,即使誤操作調用也不會出錯。  
  4.     [super dealloc];  
  5. }</span>  

 

 

 

六、property中的setter文法關鍵字

在property屬性中有三個關鍵字定義關於展開setter方法中的文法,assgin(預設),retain,copy。當然這三個關鍵字是互斥的。

1、assgin展開stter的寫法

 

[plain] view plaincopy 
  1. -(void)setEngine:(Engine*) engine  
  2. {  
  3.      _engine=engine;  
  4. }  

 

 

2、retain展開的寫法

 

[plain] view plaincopy 
  1. -(void)setEngine:(Engine*) engine  
  2. {  
  3.    if(_engine!=engine){//判斷是否重複設定  
  4.            [_engine release];//在設定之前,先release,那麼在設定的時候,就會自動將前面的一個引用release掉  
  5.            _engine=[engine retain];//多了一個引用,retainCount+1  
  6.       }  
  7.  }  

 

3、copy展開的寫法

 

[plain] view plaincopy 
  1. -(void)setEngine:(Engine*) engine  
  2. {  
  3.    if(_engine!=engine){//判斷是否重複設定  
  4.            [_engine release];//在設定之前,先release,那麼在設定的時候,就會自動將前面的一個引用release掉  
  5.            _engine=[engine copy];//多了一個引用,retainCount+1  
  6.       }  
  7.  }  

 

對於copy屬性有一點要主要,被定義有copy屬性的對象必須要符合NSCopying協議,並且你還必須實現了-(id)copyWithZone:(NSZone*)zone該方法。

 

 

可以看到,使用retain和我們上面舉得例子完全相同,所以我們可以使用property和它的retain代替之前的寫法。

 Objective-C的記憶體管理(一)黃金法則的理解

Objective-C的記憶體管理(一)黃金法則的理解

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.