自動引用計數(shù)
本書中以辦公室開關(guān)燈舉例:
假設(shè)辦公室的照明設(shè)備只有一個典唇。上班進(jìn)入辦公室的人需要照明揭蜒,所以要把燈打開彪见。
而對于下班離開的人來說丘薛,已經(jīng)不需要照明了鹿寻,所以要把燈關(guān)掉睦柴。但是如果該辦公室有很多人,該如何控制開關(guān)燈呢毡熏?
也就是最早來辦公室的人開燈坦敌,最后一個離開辦公室的人負(fù)責(zé)關(guān)燈。采用 引用計數(shù)說明的話就是:
- 辦公室沒人時引用計數(shù)為0 == 燈是關(guān)的
- 第一個人進(jìn)入辦公室引用計數(shù)為1 == 開燈
- 第二個人進(jìn)入辦公室引用計數(shù)為2 == 燈是開的
- 第三個人進(jìn)入辦公室引用計數(shù)為3 == 燈是開的 以此類推
當(dāng)下班時:
- 第一個人離開辦公室后引用計數(shù)為2 == 燈是開的
- 第二個人離開辦公室后引用計數(shù)為1 == 燈是開的
- 第三個人離開辦公室后引用計數(shù)為0 == 關(guān)燈
使用引用計數(shù)計算需要照明的人數(shù)痢法,使辦公室的照明得到了很好的管理狱窘。同樣的,使用引用計數(shù)功能财搁,對象也就能得到很好的管理蘸炸,這就是Objective-C的內(nèi)存管理。
內(nèi)存管理的思考方式:
- 自己生成的對象尖奔,自己持有
- 非自己生成的對象搭儒,自己也能持有
- 不再需要自己持有的對象時釋放
- 非自己持有的對象無法釋放
對象操作 | Objective-C方法 |
---|---|
生成并持有對象 | alloc/new/copy/mutableCopy等方法 |
持有對象 | retain方法 |
釋放對象 | release方法 |
廢棄對象 | dealloc方法 |
這些有關(guān)Objective-C內(nèi)存管理的方法,實際上不包括在該語言中提茁,而是包含在Cocoa框架中用于OS X仗嗦、iOS應(yīng)用開發(fā)。Cocoa框架中Foundation框架類庫的NSObject淚擔(dān)負(fù)內(nèi)存管理的職責(zé)甘凭。Objective-C內(nèi)存管理中的alloc/retain/release/dealloc方法分別指代NSObject類的alloc類方法、retain實例方法火邓、release實例方法和dealloc實例方法丹弱。
自己生成的對象自己持有
id obj = [[NSObject alloc]init]
id obj = [NSObject new]
alloc和new是完全一致的都是自己生成并持有對象德撬,其中Copy方法利用NSCopying協(xié)議,它的實現(xiàn)方法copyWithZone:生成并持有對象的副本躲胳,mutableCopy方法利用NSMutableCopying協(xié)議蜓洪,它的實現(xiàn)方法NSMutableCopyWithZone:生成并持有對象的副本
非自己生成的對象,自己也能持有
id obj = [NSMutableArray array]
取得對象的存在坯苹,但自己不持有對象
[obj retain]
自己持有對象
不再需要自己持有的對象時釋放
- 自己生成并持有的對象釋放
id obj = [[NSObject alloc]init]
自己生成并持有對象
obj release
釋放對象
- 非自己生成并持有的對象釋放
`id obj = [NSMutableArray array]`取得非自己生成并持有的對象
`[obj retain]`自己持有對象
`[obj release]`釋放對象
如果要用某個方法生成對象隆檀,并將其返回給該方法的調(diào)用方,又是怎么實現(xiàn)的呢粹湃?
```
-(id)allocObject {
id obj = [[NSObject alloc]init];
return obj;
}
```
調(diào)用該方法:
```
id obj1 = [obj0 allocObject];
```
那么,[NSMutableArray array]方法取得對象的存在恐仑,但自己不持有對象,又是如何實現(xiàn)的为鳄?
```
-(id)object {
id obj = [[NSObject alloc]init];// 自己持有對象
[obj autorelease];// 取得對象的存在裳仆,但自己不持有
return obj;// 返回對象
}
```
由此可以看出使用了autorelease方法將obj放入釋放池中由系統(tǒng)控制該對象的釋放,使對象在超出制定的生存范圍時能夠自動并且正確地釋放孤钦。
非自己持有的對象無法釋放
id obj = [NSMutableArray array];// 獲得非自己持有的對象
[obj release]; // 過度釋放crash
那么release和autorelease的區(qū)別在哪里歧斟?
當(dāng)對象的引用計數(shù)大于0時release就將引用計數(shù)減一,當(dāng)對象的引用計數(shù)等于0時偏形,調(diào)用dealloc實例方法静袖,廢棄對象。
}
autorelease實際上只是把對release的調(diào)用延遲了俊扭,對于每個autorelease队橙,系統(tǒng)只是將對象放入了當(dāng)前的autorelease pool中,當(dāng)該pool被釋放時统扳,該pool中的所有對象就會被release喘帚。而autorelease pool就是用來避免頻繁的申請/釋放內(nèi)存。
- 釋放池的生命周期是與Runloop有關(guān)的咒钟,盡量避免在對象釋放后使用吹由。
- 向上面提到的[NSMutableArray array]返回的對象自己并不持有,也就是說該對象已經(jīng)放入釋放池中了朱嘴,如果你想把它當(dāng)成全局對象來使用倾鲫,需要retain使引用計數(shù)+1,不需要時在release萍嬉。
我們在創(chuàng)建一個程序時乌昔,有一個默認(rèn)的autorelease pool,在程序退出時銷毀壤追,那是不是所有的對象都放入了這個釋放池中磕道,在程序退出時將其中的對象release呢?
并不是行冰,這樣來說的話溺蕉,與內(nèi)存泄露并沒有區(qū)別了伶丐。其實,對于每個Runloop系統(tǒng)都會創(chuàng)建一個autorelease pool疯特,并且這些釋放池棧式儲存哗魂,在每個Runloop結(jié)束的時候,棧頂?shù)腶utorelease pool就會被銷毀漓雅,也就是說所有的對象都會被release录别。
未完
ARC[Automatic Reference Counting]規(guī)則