關于iOS內存管理的規則思考

ijkqtnzjtctc 8年前發布 | 5K 次閱讀 iOS開發 移動開發

關于iOS內存管理的規則思考

  • 自己生成的生成的對象,自己持有。
  • 非自己生成的對象,自己也能持有。
  • 不在需要自己持有的對象時釋放。
  • 非自己持有的對象無法釋放。
注:這里的自己是對象使用的環境,理解為編程人員本身也沒有錯

對象操作和Objective-C方法對應

對象操作 Objectivew-C方法
生成并持有對象 alloc/copy/mutableCopy/new或以此開頭的方法
持有對象 retain
釋放對象 release
廢棄對象 dealloc

自己生成的對象,自己持有

//自己生成并持有對象
id obj1 = [[NSObject alloc] init];

id obj2 = [NSObject new];

id obj3 = [obj2 copy];</code></pre>

copy 方法基于NSCopying方法約定,實現類中的 copyWithZone:

mutableCopy 方法基于NSMutableCopying方法約定,實現類中的 mutableCopyWithZone:

非自己生成的對象,自己也能持有

用alloc/new/copy/mutableCopy以外的方法取得的對象,自己不是該對象的持有者。

//取的非自己生成并持有的對象,
//取得對象的存在,但自己不持有對象。

id obj = [NSMutableArray array];

id obj2 = [NSDictionary dictionary];

//自己持有對象 [obj retain];

[obj2 retain];</code></pre>

注:這里有點不好理解,我們先來看一段代碼:

//取的非自己生成并持有的對象,
//取得對象的存在,但自己不持有對象。

id unretain_obj = [NSMutableArray array];

NSLog(@"unretain_obj retain count = %lu", (unsigned long)[unretain_obj retainCount]);

//調用 release [unretain_obj release];</code></pre>

上述代碼,我們打印結果是:

2016-12-21 15:32:04.485 acm[65216:852108] unretain_obj retain count = 1

隨后調用 release 方法會導致程序崩潰!

按照引用計數來說,這時 unretain_obj 是可以被執行一次release方法的。但是為什么我們直接調用會導致程序崩潰。

我們會想最開始提到的四條思想之一:

無法釋放非自己持有的對象

這樣我們就很好理解了。雖然打印出 unretain_obj 的 retainCount 為 1 但是不能說明是因為它引用了對象。它只是單純的獲取到了對象的存在而已。

那么我們會產生一個問題。那么這個對象是誰在持有??

我們先做一個猜測:

因為 [NSMutableArray array] 是一個工廠方法,在 array 肯定是要生成一個 NSMutableArray 實例對象。這時也必然會有一個指針引用它然后返回這個對象。so。。。

先想到這里,后邊我們再去印證

我們再來看一段代碼:

//取的非自己生成并持有的對象,
//取得對象的存在,但自己不持有對象。
id unretain_obj = [NSMutableArray array];

NSLog(@"unretain_obj retain count = %lu", (unsigned long)[unretain_obj retainCount]);

//自己持有對象 [unretain_obj retain];

NSLog(@"unretain_obj retain count = %lu", (unsigned long)[unretain_obj retainCount]);

//釋放自己持有的對象 [unretain_obj release];

NSLog(@"unretain_obj retain count = %lu", (unsigned long)[unretain_obj retainCount]);</code></pre>

打印結果

2016-12-21 15:40:20.774 acm[65682:861135] unretain_obj retain count = 1

2016-12-21 15:40:20.774 acm[65682:861135] unretain_obj retain count = 2

2016-12-21 15:40:25.254 acm[65682:861135] unretain_obj retain count = 1

并且程序也不會崩潰。

著也印證了我們上邊的想法。

因為通過 retain 方法,非自己生成的對象跟用alloc/new/copy/mutableCopy方法生成并持有的對象一樣,成了自己所持有的

不在需要自己持有的對象時釋放

通過上邊的例子我們知道,自己持有的對象在釋放時調用release方法,eg:

//自己生成并持有對象
id release_obj = [[NSObject alloc] init];

//將自己持有的對象釋放 [release_obj release];

/*

  • 釋放對象
  • 指向對象的指針依然被保留在變量release_obj 中,你依然可以調用它。
  • 但是對象一經釋放絕對不可訪問,否則會造成程序崩潰。
  • 出現EXC_BAD_ACCESS Crash問題 */</code></pre>

    我們自己實現一個方法,返回一個方法調用著也可以持有的對象,即alloc的作用

    - (id)allocObject {
      //自己生成并持有對象
     id obj = [[NSObject alloc] init];
     //原封不動的返回一個由alloc方法生成的對象
     return obj;
    }

    注:方法名符合 生成并持有對象 alloc/copy/mutableCopy/new或以此開頭的方法 規則

    我們自己實現一個方法,返回一個誰也不持有的對象,只是取得對象的存在

    - (id)object {
     //自己生成并持有對象
     id obj = [[NSObject alloc] init];
    
     //調用autorelease方法 取得對象的存在,但自己不持有對象。
     [obj autorelease];
    
     return obj;
    }

    autorelease 方法可以取得對象的存在,但自己不持有對象。使對象在超出指定的生存范圍時能夠自動的并正確的釋放(調用 release 方法)

    autorelease和release方法的區別

    autorelease:

    release:

    autorelease的詳細解說我們后邊介紹。

    我們也可以通過調用 retain 方法來使 autorelease 方法的來的對象自己持有eg:

    //獲取對象的存在,自己不持有
    id unretain_obj = [NSMutableArray array];
    
    //持有對象
    [unretain_obj retain];

    無法釋放非自己持有的對象

    自己已經釋放了還繼續釋放

    //自己生成并持有對象
     id release_obj = [[NSObject alloc] init];
    
     //將自己持有的對象釋放
     [release_obj release];
    
     //釋放已經釋放的對象
     [release_obj release];
    
     /*
      * 釋放對象
      * 指向對象的指針依然被保留在變量release_obj 中,你依然可以調用它。
      * 但是對象一經釋放絕對不可訪問,否則會造成程序崩潰。
      * 出現EXC_BAD_ACCESS Crash問題
      */

    只獲取了對象的存在,試圖釋放對象

    //取的非自己生成并持有的對象,
     //取得對象的存在,但自己不持有對象。
     id unretain_obj = [NSMutableArray array];
     //釋放自己不持有的對象
     [unretain_obj release];

    程序崩潰,報EXC_BAD_ACCESS Crash問題

     

    來自:http://blog.csdn.net/wxs0124/article/details/53787357

     

 本文由用戶 ijkqtnzjtctc 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!