概要
OC中的內存管理,也就是引用計數。可以用開關燈房間的案例來說明:
假設辦公室照明設備只有一個。上班的人進入辦公室需要照明,所以把燈打開。而隊對於下班離開辦公室的人來說,已經不需要照明瞭,所以把等關掉。若是很多上下班,每個人都開燈或者關燈,那麼辦公室的情況又將如何呢?最早下班的人關燈,那麼辦公室豈不是一片黑暗。
解決這個問題的辦法是使辦公室還有至少一個人的情況下保持開燈狀態,無人的時候保持關狀態。
1. 最早進入辦公室開燈
2. 之後進入辦公室的人,需要照明
3. 下班離開辦公室的人,不需要照明
4. 最後離開辦公室的人關燈(此時已無人需要照明)
根據計數功能來計算 ”需要照明的人數”
- 第一個人進入辦公室,辦公室的計數爲1。計數:1
- 之後進入辦公室的人,疊加1。計數:2
- 每當人有人下班離開,減去1。計數:1
- 最後離開辦公室,減去1。計數:0,因此要關燈。
在OC中,”對象” 相當於辦公室的照明設備。
- 開燈 –> 生成對象
- 需要照明 –> 持有對象
- 不再需要照明 –> 釋放對象
- 關燈 –> 廢棄對象
內存管理的思考方式
- 自己生成並持有對象。
- 持有非自己生成的對象。
- 不再需要自己持有的對象時釋放。
- 非自己持有的對象無法釋放。
對象操作 | Objective-C方法 |
---|---|
生成並持有對象 | alloc/new/copy/muetableCopy等方法 |
持有對象 | retain 方法 |
釋放對象 | release 方法 |
廢棄對象 | dealloc 方法 |
自己生成並持有對象
下面寫出了自己生成並持有對象,我們使用alloc方法:
<!--自己生成並持有對象-->
id obj = [[NSObject alloc] init];
copy方法利用基於NSCopying方法約定,由各類實現copyWithZone:方法生成並持有對象的副本。與Copy方法類似,mutableCopy方法利用基於NSMutableCopying方法約定,由各類實現mutableCopyWhitZone:方法生成持有對象的副本。
這些方法生成的對象,雖然是對象的副本,但同alloc、new方法一樣,在 “自己生成並持有對象” 這點上沒有改變。
所謂自己生成,這個自己可以看做當前環境
或者編程人員
本身也沒錯。或者可以這樣理解,當前這個對象是在當前的環境生成,那麼這個對象就屬於這個當前環境
生成的,所以對象被當前環境
持有。
結論:
通過alloc/new/copy/mutableCopy
生成的對象都是 自己生成並持有對象
。
持有非自己生成的對象
<!--取得非自己生成並持有的對象-->
id obj = [NSMutableArray array];
上述源碼中,NSMutableArray類對象被賦給變量obj,但變量obj自己並不持有改對象。使用retain方法可以持有對象。
//持有對象
[obj retainl];
後續會說明爲什麼這種方式(非alloc/new/copy/mutableCopy
)生成的就是非自己生成的。
不再需要自己持有的對象時釋放
自己持有的對象,一旦不再需要,持有者有義務釋放該對象。釋放使用release
方法。
//自己生成並持有對象
id obj = [[NSObject alloc] init];
//釋放
[obj release];
自己生成並持有 和 非自己生成也能持有 的原理。
用
alloc/new/copy/mutableCopy
方法生成自己生成並持有的對象
,或者用retain
方法持有的對象,一旦不再需要,務必要用release
方法進行釋放。
現在我們通過源碼來分析:爲什麼會有自己生成並持有
和非自己生成也能持有
:
- 通過模擬
alloc/new/copy/mutableCopy
方法, 理解自己生成並持有對象
+ (NSObject *) allocObject {
//自己生成並持有對象
id obj = [[NSObject alloc] init];
//自己持有對象
retain obj;
}
原封不動地返回用 alloc
方法生成並持有對象,就能讓調用方也持有該對象。
<!--取得非自己生成並持有的對象-->
id obj1 = [NSObject allocObject];
allocObject
與用 alloc
方法生成並持有對象的情況完全相同,所有使用allocObject方法也就意味着 自己生成並持有對象
。
- 通過模擬
[NSMutableArray array]
方法, 理解非自己生成並持有對象
前面就有說到調用 [NSMutableArray array]
方法使取得的對象存在,但是自己又不持有對象,又是怎麼實現的呢?
- (id)object {
//自己生成並持有對象
id obj = [[NSObject alloc] init];
//使對象在超出指定的生成範圍時能夠自動並正確地的釋放
[obj autorelease];
//返回對象
return obj;
}
上例中,我們使用了 autorelease 方法。用該方法,可以使取得的對象存在,但是自己不持有對象。
這樣的好處就是,我們可以不用去手動去管理通過此方法 生成的對象 的釋放。
autorelease 提供這樣的功能,是對象在超出指定的生成範圍時能夠自動並正確地釋放(調用release方法)
看完這張 release 和 autorelease
圖:
相信大家已經明白爲什麼通過object
、array
方法生成的是非自己生成
,是因爲生成在生成這個對象的方法裏面,添加延遲釋放處理,而不需要我們再去調用release
釋放了。
那麼我們要如何去區分到底誰需要調用release
,誰不需要調用release
。所以引入了命名規則:
- 使用
NSMutableArray
類的array
類方法等可以取得誰都不持有的對象,這些方法都是通過autorelease
而實現的 alloc/new/copy/mutableCopy
方面名開頭的,就是自己生成並持有的對象
無法釋放非自己持有的對象
用
alloc/new/copy/mutableCopy
方法生成自己生成並持有的對象
,或者用retain
方法持有的對象,一旦不再需要,務必要用release
方法進行釋放。
而由此以外所得到的對象絕對不能釋放。倘若在應用程序中釋放了非自己所持有的對象會造成崩潰。
例如自己生成並持有對象後,在釋放完後,再次釋放。(重複調用release);
或者是在 “取得對象的存在,但是自己不持有對象” 時釋放。
都會到導致應用程序崩潰!因此絕對不要釋放非自己持有的對象!
以上五項內容,就是 “引用計數式內存管理” 的思考方式。