oc007---內存管理

  1. 什麼是內存管理
    ➢ 移動設備的內存極其有限,每個app所能佔用的內存是有限制的
    ➢ 當app所佔用的內存較多時,系統會發出內存警告,這時得回收一些不需要再使用的內存空間。比如回收一些不需要使用的對象、變量等
    ➢ 管理範圍:任何繼承了NSObject的對象,對其他基本數據類型(int、char、float、double、struct、enum等)無效
    內存管理

➢ 每個OC對象都有自己的引用計數器,是一個整數,表示“對象被引用的次數”,即有多少人正在使用這個OC對象
➢ 每個OC對象內部專門有4個字節的存儲空間來存儲引用計數器

  1. 引用計數器的作用
    ➢ 當使用alloc、new或者copy創建一個新對象時,新對象的引用計數器默認就是1
    ➢ 當一個對象的引用計數器值爲0時,對象佔用的內存就會被系統回收。換句話說,如果對象的計數器不爲0,那麼在整個程序運行過程,它佔用的內存就不可能被回收,除非整個程序已經退出

  2. 引用計數器的操作
    ➢ 給對象發送一條retain消息,可以使引用計數器值+1(retain方法返回對象本身)
    ➢ 給對象發送一條release消息,可以使引用計數器值-1
    ➢ 可以給對象發送retainCount消息獲得當前的引用計數器值

  3. 對象的銷燬
    ➢ 當一個對象的引用計數器值爲0時,那麼它將被銷燬,其佔用的內存被系統回收
    ➢ 當一個對象被銷燬時,系統會自動向對象發送一條dealloc消息
    ➢ 一般會重寫dealloc方法,在這裏釋放相關資源,dealloc就像對象的遺言
    ➢ 一旦重寫了dealloc方法,就必須調用[super dealloc],並且放在最後面調用
    ➢ 不要直接調用dealloc方法
    ➢ 一旦對象被回收了,它佔用的內存就不再可用,堅持使用會導致程序崩潰(野指針錯誤)

2.內存管理原則

  1. 誰創建,誰release
    ➢ 如果你通過alloc、new或[mutable]copy來創建一個對象,那麼你必須調用release或autorelease
    ➢ 換句話說,不是你創建的,就不用你去[auto]release

  2. 誰retain,誰release
    ➢ 只要你調用了retain,無論這個對象是如何生成的,你都要調用release

  3. 總結
    ➢ 有始有終,有加就有減
    ➢ 曾經讓對象的計數器+1,就必須在最後讓對象計數器-1

3、 set方法的內存管理
如果你有個OC對象類型的成員變量,就必須管理這個成員變量的內存。比如有個Book *_book
1. set方法的實現
- (void)setBook:(Book *)book{
if (book != _book) {
[_book release];
_book = [book retain];
}
}

  1. dealloc方法的實現
    • (void)dealloc {
      [_book release];
      [super dealloc];
      }

4、 @property參數
1. 控制set方法的內存管理
➢ retain : release舊值,retain新值(用於OC對象)
➢ assign : 直接賦值,不做任何內存管理(默認,用於非OC對象類型)
➢ copy : release舊值,copy新值(一般用於NSString *)

  1. 控制需不需生成set方法
    ➢ readwrite :同時生成set方法和get方法(默認)
    ➢ readonly :只會生成get方法

  2. 多線程管理
    ➢ atomic :性能低(默認)
    ➢ nonatomic :性能高

  3. 控制set方法和get方法的名稱
    ➢ setter : 設置set方法的名稱,一定有個冒號:
    ➢ getter : 設置get方法的名稱

5、 循環引用
1. @class
➢ 使用場景
對於循環依賴關係來說,比方A類引用B類,同時B類也引用A類
這裏寫圖片描述
這裏寫圖片描述
這種代碼編譯會報錯。當使用@class在兩個類相互聲明,就不會出現編譯報錯
➢ 用法概括
使用 @class 類名; 就可以引用一個類,說明一下它是一個類
➢ 和#import的區別
 #import方式會包含被引用類的所有信息,包括被引用類的變量和方法;@class方式只是告訴編譯器在A.h文件中 B *b 只是類的聲明,具體這個類裏有什麼信息,這裏不需要知道,等實現文件中真正要用到時,纔會真正去查看B類中信息
 如果有上百個頭文件都#import了同一個文件,或者這些文件依次被#improt,那麼一旦最開始的頭文件稍有改動,後面引用到這個文件的所有類都需要重新編譯一遍,這樣的效率也是可想而知的,而相對來 講,使用@class方式就不會出現這種問題了
 在.m實現文件中,如果需要引用到被引用類的實體變量或者方法時,還需要使用#import方式引入被引用類

  1. 循環retain
    ➢ 比如A對象retain了B對象,B對象retain了A對象
    ➢ 這樣會導致A對象和B對象永遠無法釋放

  2. 解決方案
    ➢ 當兩端互相引用時,應該一端用retain、一端用assign

6、 autorelease
1. autorelease
➢ 給某個對象發送一條autorelease消息時,就會將這個對象加到一個自動釋放池中
➢ 當自動釋放池銷燬時,會給池子裏面的所有對象發送一條release消息
➢ 調用autorelease方法時並不會改變對象的計數器,並且會返回對象本身
➢ autorelease實際上只是把對release的調用延遲了,對於每一次autorelease,系統只是把該對象放入了當前的autorelease pool中,當該pool被釋放時,該pool中的所有對象會被調用Release

  1. 自動釋放池的創建
    ➢ ios 5.0後
    @autoreleasepool
    {
    // ….
    }
    ➢ ios 5.0前
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    // …..
    [pool release]; // 或[pool drain];
    ➢ 在程序運行過程中,可以創建多個自動釋放池,它們是以棧的形式存在內存中
    ➢ OC對象只需要發送一條autorelease消息,就會把這個對象添加到最近的自動釋放池中(棧頂的釋放池)

  2. 應用實例
    ➢ 跟release的對比
     以前:

Book *book = [[Book alloc] init];
[book release];
 現在:
Book *book = [[[Book alloc] init] autorelease];
// 不要再調用[book release];

➢ 一般可以爲類添加一個快速創建對象的類方法
+ (id)book {
return [[[Book alloc] init] autorelease];
}
外界調用[Book book]時,根本不用考慮在什麼時候釋放返回的Book對象

  1. 規律
    ➢ 一般來說,除了alloc、new或copy之外的方法創建的對象都被聲明瞭autorelease
    ➢ 比如下面的對象都已經是autorelease的,不需要再release
    NSNumber *n = [NSNumber numberWithInt:100];
    NSString *s = [NSString stringWithFormat:@”jack”];
    NSString *s2 = @”rose”;
發佈了53 篇原創文章 · 獲贊 3 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章