1. 程式人生 > >黑馬程式設計師——OC基礎—記憶體管理

黑馬程式設計師——OC基礎—記憶體管理

=== 記憶體管理機制 ===

OC的區域性變數在程式碼塊結束時被系統銷燬, 記憶體被回收.

OC的物件, 內部有引用計數器, 當引用計數器的值為0時, 被系統銷燬, 記憶體被回收.

區域性變數存放在棧中. 物件存放在堆中.

注意, 物件指標還是存放在棧中, 物件本身佔用的記憶體存放在堆中.

在OC中, 我們要對自己寫的繼承了NSObject的物件進行記憶體管理.

物件在建立(alloc, new, copy)時, 引用計數器的值為1.

物件呼叫retain方法, 引用計數器的值+1.

物件呼叫release方法, 引用計數器的值-1.

使用retainCount返回引用計數器的值. (unsigned long)

當物件的引用計數器的值為0時, 物件就會被系統銷燬, 記憶體被回收.

物件被銷燬時, 系統會呼叫物件的dealloc方法. 重寫dealloc方法釋放相關資源, 證實物件被回收. dealloc方法最後要呼叫[super dealloc];

野指標: 在物件被銷燬後, 把指標設為nil. 使用野指標呼叫方法, 會發生錯誤.

=== 物件的記憶體管理 ===

[main函式中]

每使用alloc, new, copy一次, 就release一次. 並設空指標.

每使用retain一次, 就release一次.

注意: NSString *物件不是alloc產生的, 所以不用release.

當給這個物件設定物件屬性時, 要給屬性物件的計數器+1.

當這個物件切換物件屬性時, 要給原有的屬性物件計數器-1, 給新的屬性物件計數器+1. 但是要注意新物件和原物件是否是同一個物件.

當這個物件被釋放時, 要給它的所有屬性物件的計數器-1.

set方法的寫法注意:

1 要release原來的屬性物件

2 要retain新加的屬性物件

3 要判斷要替換的屬性物件和現有的是否是同一個物件, 如果是, 就不要release

dealloc方法的重寫:

1 釋放所有的物件型別的屬性

2 呼叫[super dealloc];

3 列印內容, 方便檢視是不是所有建立的物件都被釋放.

#  使用 @property 的引數生成恰當的set方法  

@property的引數:

assign, retain, copy

nonatomic, atomic

readonly, readwrite

setter = setName:, getter = getName

基本資料型別的屬性, 使用assign引數

OC物件的屬性, 使用retain引數

字串型別的屬性, 通常使用copy引數

使用retain, 編譯器會根據@property生成上面那種三行管理記憶體的setter方法.

使用assign, 編譯器會根據@property生成一行直接賦值的setter方法. 

使用copy, 編譯器會生成使用copy的setter方法, 使得屬性是原字串的拷貝.

因為如果雙方在宣告中都互相#import, 會造成迴圈引用.

以後只要一個類包含的屬性是另一個類, 在類的宣告中使用@class, 在實現中使用#import

@class 類名

這樣就宣告類,但是如果需要用到該類中的成員變數或者方法,則還需要使用#import

# 釋放池

對小記憶體的物件, 可以使用 @autorelease 代替 release. 使用@autorelease的物件在釋放池被銷燬時被release一次.

可以在類中提供類方法直接建立autorelease的物件, 注意在新建物件時, 使用 [self alloc] 而不是 [類名 alloc] 以方便子類呼叫時能夠返回子類的物件. 這樣的類方法通常以類名開頭. 系統自帶的這類方法也是帶有autorelease的.

[[[類名 alloc] init] autorelease];

上述程式碼在釋放池中,可以不用在最後呼叫物件的release方法。它會在釋放池結束的時候自動讓計數器-1.

=== 記憶體管理知識點總結 ===

1 在main函式中

        1> 有alloc就要release

        2> 有retain 就release

2 物件型別的屬性的set方法的三要素:

        1> 判斷是否是同一物件

        2> release原來的物件

        3> retain新設的物件, 並設定為屬性

        4> 注意: 如果兩個類互為對方的屬性, 一邊使用retain, 另一邊直接賦值(assign).

3 重寫dealloc方法:

        1> 釋放所有在set方法中retain過的屬性

        2> 可以列印內容, 方便檢查是否所有新建的物件都在程式結束前被釋放

        3> 要呼叫[super release];

4 原則

        1> 誰alloc, 誰release

        2> 誰retain, 誰release

        3> 不是自己alloc的就不需要release, 比如很多靜態方法建立的物件就不需要release

5 在類的宣告中使用@class, 在類的實現中使用#import, 提高效率, 並避免互相迴圈#import

=== ARC 的使用 ===

ARC是編譯器特性, 預設指向物件的指標都是強指標, 使用__weak標記的是弱指標. 如果沒有強指標指向物件了,這個物件就會被銷燬 (編譯器會自動新增 retain, release程式碼). 如果物件被銷燬了, 指向它弱指標會被自動清空, 以防野指標錯誤.

ARC的使用:

        1. 即使有alloc也不需要寫release或autorelease, 不允許使用retain.

        2. set方法對物件型別的屬性使用strong代替retain

        2. 不需要在dealloc方法中釋放屬性

也就是說, 有了ARC就不需要關注記憶體管理了, 怎麼寫都不會錯.