原理:
- 每個(gè)對(duì)象內(nèi)部都保存了一個(gè)與之相關(guān)聯(lián)的整數(shù),稱為引用計(jì)數(shù)器(auto reference count)
- 每當(dāng)使用alloc、new或者copy創(chuàng)建一個(gè)對(duì)象時(shí),對(duì)象的引用計(jì)數(shù)器被設(shè)置為1
- 給對(duì)象發(fā)送一條retain消息(即調(diào)用retain方法),可以使引用計(jì)數(shù)器值+1
- 給對(duì)象發(fā)送一條release消息,可以使引用計(jì)數(shù)器值-1
- 當(dāng)一個(gè)對(duì)象的引用計(jì)數(shù)器值為0時(shí),那么它將被銷毀,其占用的內(nèi)存被系統(tǒng)回收,OC也會(huì)自動(dòng)向?qū)ο蟀l(fā)送一條dealloc消息。一般會(huì)重寫dealloc方法,在這里釋放相關(guān)資源。一定不要直接調(diào)用dealloc方法。
- 可以給對(duì)象發(fā)送retainCount消息獲得當(dāng)前的引用計(jì)數(shù)器值。
基本原則:
MRC:
- 內(nèi)存管理遵循“誰(shuí)創(chuàng)建,誰(shuí)釋放,誰(shuí)引用,誰(shuí)管理”的機(jī)制,當(dāng)通過(guò)alloc、new或者(mutable)copy來(lái)創(chuàng)建一個(gè)對(duì)象,必須調(diào)用release或autorelease(autorelease是延遲釋放內(nèi)存,不用你自己去手動(dòng)釋放,系統(tǒng)會(huì)知道在什么時(shí)候該去釋放掉它。),當(dāng)通過(guò)retain引用一個(gè)對(duì)象的時(shí)候,需要調(diào)用release。當(dāng)對(duì)象引用計(jì)數(shù)為0時(shí),系統(tǒng)將釋放該對(duì)象,這是OC的手動(dòng)管理內(nèi)存機(jī)制。
ARC:
- iOS 5.0之后引用自動(dòng)管理機(jī)制——自動(dòng)引用計(jì)數(shù),管理機(jī)制與手動(dòng)機(jī)制一樣,只是不再需要調(diào)用retain、release、autorelease;它編譯時(shí)的特性,當(dāng)你使用ARC時(shí),在適當(dāng)位置插入release和autorelease;它引用strong和weak關(guān)鍵字,
strong修飾的指針變量指向?qū)ο髸r(shí),當(dāng)指針指向新值或者指針不復(fù)存在,相關(guān)聯(lián)的對(duì)象就會(huì)自動(dòng)釋放,而weak修飾的指針變量指向?qū)ο螅?dāng)對(duì)象的擁有者指向新值或者不存在時(shí)weak修飾的指針會(huì)自動(dòng)置為nil。
- 如果使用alloc、copy(mutableCopy)或者retian一個(gè)對(duì)象時(shí),你就有義務(wù),向它發(fā)送一條release或者autorelease消息。其他方法創(chuàng)建的對(duì)象,不需要由你來(lái)管理內(nèi)存。
- 向一個(gè)對(duì)象發(fā)送一條autorelease消息,這個(gè)對(duì)象并不會(huì)立即銷毀,而是將這個(gè)對(duì)象放入了自動(dòng)釋放池,待池子釋放時(shí),它會(huì)向池中每一個(gè)對(duì)象發(fā)送一條release消息,以此來(lái)釋放對(duì)象。
- 向一個(gè)對(duì)象發(fā)送release消息,并不意味著這個(gè)對(duì)象被銷毀了,而是當(dāng)這個(gè)對(duì)象的引用計(jì)數(shù)為0時(shí),系統(tǒng)才會(huì)調(diào)用dealloc方法,釋放該對(duì)象和對(duì)象本身它所擁有的實(shí)例。
注意事項(xiàng):
- 如果一個(gè)對(duì)象有一個(gè)strong類型的指針指向著,這個(gè)對(duì)象就不會(huì)被釋放。如果一個(gè)指針指向超出了它的作用域,就會(huì)被指向nil。如果一個(gè)指針被指向nil,那么它原來(lái)指向的對(duì)象就被釋放了。當(dāng)一個(gè)視圖控制器釋放時(shí),它內(nèi)部的全局指針會(huì)被指向nil。
- 局部變量:出了作用域,指針會(huì)被置為nil。
- 方法內(nèi)部創(chuàng)建對(duì)象,外部使用需要添加autorelease。
- Xib連線的時(shí)候,用weak修飾。
- 代理MRC使用assign修飾,ARC使用weak修飾。
- block使用copy修飾。
- block中為了避免循環(huán)引用(常見(jiàn)self持有的block)問(wèn)題,使用__weak方式。
- 聲明屬性時(shí),不要以new開(kāi)頭。如果非要以new開(kāi)頭命名屬性的名字,需要自己定制get方法名,如:
@property(getter = theString) NSString *newString; - 如果要使用自動(dòng)釋放池,用@autoreleasepool{} 。
- ARC只能管理Foundation框架的變量,如果程序中把Foundation中的變量強(qiáng)制換成COre Foundation中的變量需要交換管理權(quán)。
- 在非ARC工程中采用ARC去編譯某些類:-fobjc-arc。
- 在ARC下的工程采用非ARC去編譯某些類:-fno-fobjc-arc。
MRC內(nèi)存管理測(cè)試:
Student類:
@interface Student : NSObject {
int age;
}
@property int age;
@end
@implementation Student
@synthesize age;
//重寫dealloc方法,當(dāng)引用計(jì)數(shù)器(auto reference count)為零的時(shí)候調(diào)用。
- (void)dealloc {
NSLog(@"%@被銷毀了",self);
[super dealloc];
}
@end
Controller類:
Student *stu = [[Student alloc]init];// alloc一次,引用計(jì)數(shù)器為1
// Student *stu = [[[Studnet alloc]init] autorelease];// 這樣寫的話系統(tǒng)會(huì)在適當(dāng)?shù)牡胤綄?duì)stu的內(nèi)存進(jìn)行自動(dòng)回收,就不用自己寫release回收了
// z代表無(wú)符號(hào)
NSLog(@"count:%zi", [stu retainCount]);
[stu retain];// 引用計(jì)數(shù)器變?yōu)?
NSLog(@"count:%zi", [stu retainCount]);
[stu release];// 引用計(jì)數(shù)器變?yōu)?
NSLog(@"count:%zi", [stu retainCount]);
[stu release];// release一次,引用計(jì)數(shù)器減1,變?yōu)?然后會(huì)調(diào)用dealloc方法
運(yùn)行結(jié)果:
2017-04-20 23:51:51.041 **[93035:36023785] count:1
2017-04-20 23:51:51.041 **[93035:36023785] count:2
2017-04-20 23:51:51.041 **[93035:36023785] count:1
2017-04-20 23:51:51.041 **[93035:36023785] <Student: 0x100109a80>被銷毀了
------隨筆