自動引用計數(shù)
- 什么是自動引用計數(shù)
- 內(nèi)存管理/引用計數(shù)
- ARC規(guī)則
- ARC的實現(xiàn)
1.1 什么是自動引用計數(shù)
- ARC和MRC的區(qū)別:
MRC:(Manual Reference Counting)也就是非ARC崩溪,在Xcode4之前伶唯,Object_C的內(nèi)存管理就需要開發(fā)人員手動維護乳幸。
ARC:(Automatic Reference Counting)也就是ARC粹断,翻譯成中文就是:【自動引用計數(shù)】瓶埋,不需要開發(fā)人員手動維護养筒,系統(tǒng)會在合適的時候調(diào)用內(nèi)存管理方法晕粪。
顧名思義巫湘,自動引用計數(shù)(ARC尚氛,Automatic Reference Counting)是指內(nèi)存管理中對引用采取自動計數(shù)的技術(shù)阅嘶。以下摘自蘋果的官方說明奈懒。
在Objective-C中采用Automatic Reference Counting(ARC)機制磷杏,讓編輯器來進行內(nèi)存管理极祸。在新一代的Apple LLVM編輯器中設(shè)置ARC為有效狀態(tài)遥金,就無需再次鍵入retain或release代碼稿械,這在降低程序崩潰美莫、內(nèi)存泄漏等風險的同時厢呵,很大程度上減少了開發(fā)程序的工作量襟铭。編譯器完全清楚目標對象寒砖,并能立刻釋放那些不再被使用的對象入撒。如此一來茅逮,應(yīng)用程序?qū)⒕哂锌深A(yù)測性献雅,且能流程運行挺身,速度也將大幅提升章钾。
1.2 內(nèi)存管理/引用計數(shù)
可以用開關(guān)房間的燈為例來說明引用計數(shù)的機制贱傀。
加入辦公室里的照明設(shè)備只有一個府寒。上班進入辦公室的人需要照明株搔,所以要開燈纵隔,下班離開辦公室的人不需要照明巨朦,所以要把燈關(guān)掉糊啡。若是很多人上下班棚蓄,每個人都開燈或者關(guān)燈梭依,那么辦公室的情況又將如何呢役拴?最早下班離開的人如果關(guān)了燈河闰,那辦公室還沒走的所有人都將處于一片黑暗之中姜性。
解決這一問題的辦法是使辦公室在還有至少1人的情況下保持開燈狀態(tài)部念,而在無人時保持關(guān)燈狀態(tài)妓湘。
(1)最早進入辦公室的人開燈榜贴。
(2)之后進入辦公室的人,需要照明秆麸。
(3)下班離開辦公室的人沮趣,不需要照明房铭。
(4)最后離開辦公室的人關(guān)燈(此時已無人需要照明)缸匪。
為判斷是否還有人在辦公室,這里導入計數(shù)功能來計算“需要照明的人數(shù)”砂心。下面讓我們看看這一功能如何運作的辩诞。
如下圖:(1)第一個人進入辦公室译暂,“需要照明的人數(shù)”加1秧秉。計數(shù)值從0變成了1荧嵌,因此要開燈啦撮。
(2)之后每當有人進入辦公室赃春,“需要照明的人數(shù)”就加1.如計數(shù)值從1變成2。
(3)每當有人下班離開辦公室狭吼,“需要照明的人數(shù)”就減1刁笙。如計數(shù)值從2變成1疲吸。
(4)最后一個人下班離開辦公室時,“需要照明的人數(shù)”減1烦租。計數(shù)值從1變成了0叉橱,因此要關(guān)燈窃祝。
在Objective-C中大磺,“對象”相當于辦公室的照明設(shè)備杠愧。“對象的使用環(huán)境”相當于上班進入辦公室的人绳瘟。上班進入辦公室的人對辦公室照明設(shè)備發(fā)出的動作糖声,與Objective-C中的對應(yīng)關(guān)系如表1-1所示分瘦。
表1-1 對辦公室照明設(shè)備所做的動作和對Objective-C的對象所做的動作
對照明設(shè)備所做的動作 | 對Objective-C對象所做的動作 |
---|---|
開燈 | 生成對象 |
需要照明 | 持有對象 |
不需要照明 | 釋放對象 |
關(guān)燈 | 廢棄對象 |
內(nèi)存管理的思考方式
首先來學習引用計數(shù)式內(nèi)存管理的思考方式蘸泻。看到“引用計數(shù)”這個名稱嘲玫,我們便會不自覺的聯(lián)想到“某處有某物多少多少”而將注意力放到計數(shù)上悦施。但其實,更加客觀趁冈、正確的思考方式是:
- 自己生成的對象拜马,自己持有渗勘。
- 非自己生成的對象,自己也能持有俩莽。
- 不再需要自己持有的對象時釋放旺坠。
- 非自己持有的對象無法釋放。
上文出現(xiàn)了“生成”扮超、“持有”取刃、“釋放”三個詞。而在Objective-C內(nèi)存管理中還要加上“廢棄”一詞出刷,各個詞表示的Objective-C方法如表1-2璧疗。
表1-2 對象操作與Objective-C方法的對應(yīng)
對照明設(shè)備所做的動作 | 對Objective-C對象所做的動作 | Object-C方法 |
---|---|---|
開燈 | 生成對象 | alloc/new/copy/mutableCopy等方法 |
需要照明 | 持有對象 | retain方法 |
不需要照明 | 釋放對象 | release方法 |
關(guān)燈 | 廢棄對象 | dealloc方法 |
自己生成的對象,自己持有
使用以下名稱開頭的方法名意味著自己生成的對象只有自己持有:
- alloc
- new
- copy
- mutableCopy
/*
* 自己生成并持有對象
*/
id obj = [[NSObject alloc] init];
/*
* 自己持有對象
*/
copy方法利用基于NSCopying方法約定馁龟,由各類實現(xiàn)的copyWithZone:方法生成并持有對象的副本崩侠。與copy方法類型,mutableCopy方法利用基于NSMutableCopying方法約定坷檩,由各類實現(xiàn)的mutableCopyWithZone:方法生成并持有對象的副本却音。兩者的區(qū)別在于改抡,copy方法生成不可變更的對象,而mutableCopy方法生成可變更的對象系瓢。
非自己生成的對象阿纤,自己也能持有
/*
* 取得非自己生成的對象
*/
id obj = [[NSMutableArray array];
/*
* 取得的對象存在,但自己不持有對象
*/
[obj retain];
/*
* 自己持有對象
*/
通過retain方法夷陋,非自己生成的對象跟用alloc/new/copy/mutableCopy方法生成并持有的對象一樣欠拾,成為了自己所持有的。
不再需要自己持有的對象時釋放
/*
* 取得非自己生成的對象
*/
id obj = [[NSMutableArray array];
/*
* 取得的對象存在肌稻,但自己不持有對象
*/
[obj release];
/*
* 釋放對象
* 對象一經(jīng)釋放絕對不可訪問清蚀。
*/
無法釋放非自己持有的對象
/*
* 取得非自己生成的對象
*/
id obj = [[NSMutableArray array];
/*
* 取得的對象存在,但自己不持有對象
*/
[obj release];
/*
* 對象已釋放
*/
[obj release];
/*
* 釋放之后再次釋放已非自己持有的對象爹谭!應(yīng)用程序崩潰枷邪!
* 崩潰情況:
* 再度廢棄一經(jīng)廢棄了的對象時崩潰,訪問一經(jīng)廢棄的對象時崩潰诺凡。
*/
或者在“取得的對象存在东揣,但自己不持有對象”時釋放,也會造成程序崩潰腹泌。
以上四項內(nèi)容嘶卧,就是“引用計數(shù)式內(nèi)存管理”的思考方式。
關(guān)于引用計數(shù)器:
每個OC對象都有自己的引用計數(shù)器凉袱,是一個整數(shù)表示對象被引用的次數(shù)芥吟,即現(xiàn)在有多少東西在使這個對象。對象剛被創(chuàng)建時专甩,默認計數(shù)器值為1钟鸵,當計數(shù)器的值變?yōu)?時,則對象銷毀涤躲。
在每個OC對象內(nèi)部棺耍,都專門有4個字節(jié)的存儲空間來存儲引用計數(shù)器。
引計數(shù)器的作用
判斷對象要不要回收的唯一依據(jù)就是計數(shù)器是否為0种樱,若不為0則存在蒙袍。
操作:
當一個對象的引用計數(shù)器為0時,那么它將被銷毀嫩挤,其占用的內(nèi)存被系統(tǒng)回收害幅。一旦對象被回收了,那么他所占據(jù)的存儲空間就不再可用岂昭,堅持使用會導致程序崩潰(野指針錯誤)以现。
#pragma mark -------------C語言里面malloc 用法-------------------
char *p = (char *)malloc(100);//C語言的動態(tài)分配 手動申請了100個字節(jié)的存儲空間
strcpy(p, "niming");//將字符串存儲到 指針變量p指向的內(nèi)存空間
puts(p);//輸出
free(p);//釋放
#pragma mark ------------- OC內(nèi)存管理 release 實例----------------
/*
* 自己生成并持有對象
*/
id obj = [[NSObject alloc] init];
// 或
id obj = [NSObject new];
/*
* 釋放對象
* 對象不可再被訪問
*/
[obj release];
內(nèi)存管理基本原則(黃金法則)
1.如果你通過alloc,new,copy等開頭的方法,來創(chuàng)建了一個對象,那么你就必須調(diào)用release或者autorelease方法
2.誰創(chuàng)建叼风,誰release (個人顧個人原則)
3.誰retain取董,誰release(只要你調(diào)用了retain,無論這個對象是如何生成的无宿,你都要調(diào)用release)
總結(jié):有始有終茵汰,有加就應(yīng)該有減,曾經(jīng)讓某個對象計數(shù)器+1孽鸡,就應(yīng)該讓其在最后-1
dealloc(對象的銷毀)
/*
*(1)一定要[super dealloc]蹂午, 且要放到最后
*(2)對self(當前)所擁有的的其他對象做一次release操作
*/
- (void)dealloc {
[obj release];
[super dealloc];
}
當一個對象的引用計數(shù)器為0時,那么它將被銷毀彬碱,其占用的內(nèi)存被系統(tǒng)回收豆胸。當對象被銷毀時,系統(tǒng)會自動向?qū)ο蟀l(fā)送一條dealloc消息巷疼,一般會重寫dealloc方法晚胡,在這里釋放相關(guān)的資源,dealloc就像是對象的“臨終遺言”嚼沿。一旦重寫了dealloc方法就必須調(diào)用[super dealloc]估盘,并且放在代碼塊的最后調(diào)用(不能直接調(diào)用dealloc方法)。
給對象發(fā)送消息骡尽,進行相應(yīng)的計數(shù)器操作遣妥。
retain消息:使計數(shù)器+1,該方法返回對象本身
release消息:使計數(shù)器-1(并不代表釋放對象)
retainCount消息:獲得對象當前的引用計數(shù)器值
autorelease
說到Objective-C內(nèi)存管理攀细,就不能不提autorelease箫踩。
顧名思義,autorelease就是自動釋放谭贪。這看上去很像ARC境钟,但實際上它更類似于C語言中自動變量(局部變量)的特性。
我們來復習一下C語言的自動變量故河。程序執(zhí)行時吱韭,若某自動變量超出其作用域吆豹,該自動變量將被自動廢棄鱼的。
autorelease會像C語言的自動變量那樣對待對象實例。當超出其作用域(相當于變量作用域)時痘煤,對象實例的release實例方法被調(diào)用凑阶。另外,同C語言的自動變量不同的是衷快,編程人員可以設(shè)定變量的作用域宙橱。
#pragma mark -- ios 5.0之前的創(chuàng)建方式
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
id obj = [[NSObject alloc] init];
[obj autorelease];
[pool darin];// 此處等同于 “[obj release]”
#pragma mark -- 5.0之后
@autoreleasepool {//代表開始創(chuàng)建自動釋放池
// insert code here...
NSLog(@"Hello, World!");
Person *person = [[Person alloc] init];
[person autorelease];
}//結(jié)束自動釋放池
1.系統(tǒng)自帶的方法中,如果不包含 alloc new copy等關(guān)鍵字,則這些方法返回的對象 都是 autorelease
如: [NSDate date];
如 :
id array = [NSMutableArray arrayWithCapacity:1];
此源代碼等同于以下源代碼师郑。
id array = [[[NSMutableArray alloc] initWithCapacity:1] autorelease];
1.3 ARC規(guī)則
“引用計數(shù)式內(nèi)存管理”本質(zhì)在ARC中并沒有變化环葵,ARC只是自動地幫助我們處理“引用計數(shù)”的相關(guān)部分。在編譯單位上宝冕,可設(shè)置ARC有效或無效张遭。指定編譯器屬性為“-fobjc-arc”。
與Java的對比
在java中地梨,內(nèi)存管理由JVM完全負責菊卷,java中的“垃圾回收器”負責自動回收無用對象占據(jù)的內(nèi)存資源,這樣可以大大減少程序猿在內(nèi)存管理上花費的時間宝剖,可以更集中于業(yè)務(wù)邏輯和具體功能實現(xiàn)洁闰;但這并不是說java有了垃圾回收器程序猿就可以高枕無憂,將內(nèi)存管理拋之腦外了万细!一方面扑眉,實際上java中還存在垃圾回收器沒法回收以某種“特殊方式”分配的內(nèi)存的情況;另一方面赖钞,java的垃圾回收是不能保證一定發(fā)生的襟雷,除非JVM面臨內(nèi)存耗盡的情況。所以java中部分對象內(nèi)存還是需要程序猿手動進行釋放仁烹,合理地對部分對象進行管理可以減少內(nèi)存占用與資源消耗耸弄。
java的對象內(nèi)存狀態(tài)&&引用形式及回收時機,如下圖:
-
如何判斷java對象需要被回收卓缰?GC判斷方法
- 引用計數(shù)计呈,引用計數(shù)法記錄著每一個對象被其它對象所持有的引用數(shù),被引用一次就加一征唬,引用失效就減一捌显;引用計數(shù)器為0則說明該對象不再可用;當一個對象被回收后总寒,被該對象所引用的其它對象的引用計數(shù)都應(yīng)該相應(yīng)減少扶歪,它很難解決對象之間的相互循環(huán)引用問題循環(huán)引用實例
- 可達性分析算法:從GC Root對象向下搜索其所走過的路徑稱為引用鏈,當一個對象不再被任何的GC root對象引用鏈相連時說明該對象不再可用摄闸,GC root對象包括四種:方法區(qū)中常量和靜態(tài)變量引用的對象善镰,虛擬機棧中變量引用的對象,本地方法棧中引用的對象; 解決循環(huán)引用是因為GC Root通常是一組特別管理的指針年枕,這些指針是tracing GC的trace的起點炫欺。它們不是對象圖里的對象,對象也不可能引用到這些“外部”的指針熏兄。
- 采用引用計數(shù)算法的系統(tǒng)只需在每個實例對象創(chuàng)建之初品洛,通過計數(shù)器來記錄所有的引用次數(shù)即可树姨。而可達性算法,則需要再次GC時桥状,遍歷整個GC根節(jié)點來判斷是否回收
java對象的四種引用
- 強引用 :創(chuàng)建一個對象并把這個對象直接賦給一個變量帽揪,eg :Person person = new Person(“sunny”); 不管系統(tǒng)資源有么的緊張,強引用的對象都絕對不會被回收辅斟,即使他以后不會再用到台丛。
- 軟引用 :通過SoftReference類實現(xiàn),eg : SoftReference p = new SoftReference(new Person(“Rain”));內(nèi)存非常緊張的時候會被回收砾肺,其他時候不會被回收挽霉,所以在使用之前要判斷是否為null從而判斷他是否已經(jīng)被回收了。
- 弱引用 :通過WeakReference類實現(xiàn)变汪,eg : WeakReference p = new WeakReference(new Person(“Rain”));不管內(nèi)存是否足夠侠坎,系統(tǒng)垃圾回收時必定會回收
- 虛引用 :不能單獨使用,主要是用于追蹤對象被垃圾回收的狀態(tài)裙盾,為一個對象設(shè)置虛引用關(guān)聯(lián)的唯一目的是希望能在這個對象被收集器回收時收到一個系統(tǒng)通知实胸。通過PhantomReference類和引用隊列ReferenceQueue類聯(lián)合使用實現(xiàn)
點我了解更多JAVA的內(nèi)管管理機制
再次回到OC——>
所有權(quán)修飾符
id __strong obj0;
id __weak obj1;
id __autoreleasing obj2;
// __strong,__weak,__autoreleasing可以保證附有這些修飾符的自動變量初始化為nil
// 上面源碼和下面效果等同
id __strong obj0 = nil;
id __weak obj1 = nil;
id __autoreleasing obj2 = nil;
__strong修飾符
__strong修飾符是id類型和對象類型默認的所有權(quán)修飾符。也就是說番官,以下源代碼中的id變量庐完,實際上被附加了所有權(quán)修飾符。
id obj = [[NSObject alloc] init];
id和對象類型在沒有明確指定所有權(quán)修飾符時徘熔,默認為__strong修飾符门躯。上面的源代碼與以下相同。
id __strong obj = [[NSObject alloc] init];
該源代碼在ARC無效時的表述為:
/* ARC 無效 */
id obj = [[NSObject alloc] init];
該源代碼一看則明酷师,目前在表面上沒有任何變化讶凉。再看看下面的代碼。
{
id __strong obj = [[NSObject alloc] init];
}
此源代碼明確指定了C語言的變量作用域山孔。ARC無效時懂讯,該源代碼可記述如下:
/* ARC 無效 */
{
id __strong obj = [[NSObject alloc] init];
[obj release];
}
為了釋放生詞并持有的對象,增加了調(diào)用release方法的代碼台颠。動作同先前ARC有效時動作完全一樣褐望。
如“strong”這個名稱所示,__strong修飾符表示對對象的“強引用”串前。持有強引用的變量在超出其作用域時被廢棄瘫里,隨著強引用的失效,引用的對象會隨之釋放酪呻。
{
/*
* 自己生成并持有對象
*/
id __strong obj = [[NSObject alloc] init];
/*
* 因為變量 obj 為強引用减宣,
* 所以自己持有對象
*/
}
/*
* 因為變量 obj 超出其作用域盐须,強引用失效玩荠,
* 所以自動地釋放自己持有的對象。
* 對象的所有者不存在,因此廢棄該對象阶冈。
*/
此處闷尿,對象的所有者和對象的生存周期是明確的。那么女坑,在取得非自己生成并持有的對象時又會如何呢填具?
{
id ___strong obj = [NSMutableArray array];
}
在NSMutableArray 類的 array 類方法的源代碼中取得非自己生成的對象,具體如下:
{
/*
* 取得非自己生成的對象
*/
id ___strong obj = [NSMutableArray array];
/*
* 因為變量 obj 為強引用匆骗,
* 所以自己持有對象
*/
}
/*
* 因為變量 obj 超出其作用域劳景,強引用失效,
* 所以自動地釋放自己持有的對象碉就。
*/
附有__strong修飾符的變量之間可以相互賦值盟广。
正如蘋果宣稱的那樣,通過__strong修飾符瓮钥,不必再次鍵入retain或release筋量,完美地滿足了“引用計數(shù)式內(nèi)存管理的思考方式”。因為id類型和對象類型的所有權(quán)修飾符默認為__strong修飾符碉熄,所以不需要寫上“__strong”桨武。使ARC有效及簡單的編程遵循了Objective-C內(nèi)存管理的思考方式。
__weak修飾符
__weak用來避免“循環(huán)引用”問題锈津。
例如前面出現(xiàn)帶有__strong 修飾符的成員變量在持有對象時呀酸,很容易發(fā)生循環(huán)引用。
@interface Test : NSObject
{
id __strong obj_;
}
- (void)setObject:(id __strong)obj;
@end
@implementation Test
- (id)init
{
self = [super init];
return self;
}
- (void)setObject:(id __strong)obj
{
obj_ = obj;
}
以下為循環(huán)引用琼梆。
{
id test0 = [[Test alloc] init]; // 對象A 七咧。test0持有Test對象A的強引用
id test1 = [[Test alloc] init]; // 對象B。 test1持有Test對象B的強引用
[test0 setObject:test1];
/*
* Test 對象 A 的 obj_成員變量持有Test對象 B 的強引用叮叹。
*
* 此時艾栋,持有Test對象 B 的強引用的變量為
* Test 對象 A 的obj_和test1。
*/
[test1 setObject:test1];
/*
* Test 對象 B 的 obj_成員變量持有Test對象 A 的強引用蛉顽。
*
* 此時蝗砾,持有Test對象 A 的強引用的變量為
* Test 對象 B 的obj_和test0。
*/
}
/*
* 因為 test0 變量超出其作用域携冤,強引用失效悼粮。
* 所以自動釋放 Test 對象 A。
*
* 因為 test1 變量超出其作用域曾棕,強引用失效扣猫。
* 所以自動釋放 Test 對象 B。
*
* 此時翘地,持有Test對象 A 的強引用的變量為
* Test 對象 B 的obj_申尤。
*
* 此時癌幕,持有 Test 對象 B 的強引用的變量為
* Test 對象 A 的obj_。
*
* 發(fā)生內(nèi)存泄漏昧穿!
*/
循環(huán)引用容易發(fā)生內(nèi)存泄漏勺远。所謂內(nèi)存泄漏就是應(yīng)當廢棄的對象在超出其生存周期后繼續(xù)存在。
像下面這種情況时鸵,雖然只有一個對象胶逢,但在該對象持有其自身時,也會發(fā)生循環(huán)引用(自引用)饰潜。
id test = [[Test alloc] init];
[test setObject:test];
__weak 修飾符與 __strong 修飾符相反初坠,提供弱引用。弱引用不能持有對象實例彭雾。
{
/*
* 自己生成并持有對象
*/
id ___strong obj0 = [[NSObject alloc] init];
/*
* 因為變量 obj0 為強引用某筐,
* 所以自己持有對象
*/
id __weak obj1 = obj0;
/*
* 因為變量 obj0 為強引用,
* 所以自己持有對象
*/
}
/*
* 因為變量 obj0 超出其作用域冠跷,強引用失效南誊,
* 所以自動地釋放自己持有的對象。
* 因為對象的所有者不存在蜜托,所以廢棄該對象抄囚。
*/
__weak 修飾符還有另一有點。在持有某對象的弱引用時橄务,若該對象被廢棄幔托,則此弱引用將自動失效且處于nil被復制的狀態(tài)(空弱應(yīng)用)。如以下代碼所示蜂挪。
id __weak obj1 = nil;
{
id __strong obj0 = [[NSObject alloc] init];
obj1 = obj0;
NSLog(@"A: %@", obj1);
}
NSLog(@"B: %@", obj1);
此源代碼執(zhí)行結(jié)果如下:
A: <NSObject: 0x753e180>
B: (null)
遺憾的是重挑,__weak 修飾符只能用于iOS5以上及OS X Lion以上版本的應(yīng)用程序。在iOS4以及OS X Snow Leopard的應(yīng)用程序中使用__unsafe_unretained 修飾符來代替棠涮。
__unsafe_unretained 修飾符
__unsafe_unretained 修飾符正如其名unsafe所示谬哀,是不安全的所有權(quán)修飾符。
- __unsafe_unretained: 不會對對象進行retain,當對象銷毀時,會依然指向之前的內(nèi)存空間(野指針)
- __weak: 不會對對象進行retain,當對象銷毀時,會自動指向nil
已經(jīng)有了__weak 為什么還要保留 __unsafe_unretained 严肪?
__autoreleasing 修飾符
ARC有效時不能使用autorelease方法史煎,也不能使用NSAutoreleasePool類。雖然autorelease無法直接使用驳糯,但實際上篇梭,ARC有效時 autolease功能是起作用的。
/* ARC 無效 */
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
id obj = [[NSObject alloc] init];
[obj autorelease];
[pool darin];// 此處等同于 “[obj release]”
ARC有效時酝枢,鈣源代碼也能寫成下面這樣恬偷,
@autoreleasepool {
id __autoreleasing obj = [[NSObject alloc] init];
}
指定“@autoreleasepool塊”來代替“NSAutoreleasePool類對象生成、持有以及廢棄”這一范圍帘睦。
另外袍患,ARC有效時坦康,要通過將對象賦值給附加了 __autoreleasing修飾符的變量來代替調(diào)用autorelease方法。對象賦值給附有__autoreleasing修飾符的變量等價于在ARC無效時調(diào)用對象的autorelease方法协怒,即對象被注冊到autoreleasepool涝焙。
但是卑笨,顯示地附加 __autoreleasing修飾符同顯示地附加__strong修飾符一樣罕見孕暇。
編譯器會檢查方法名是否以alloc/new/copy/mutableCopy開始,如果不是則自動將返回值的對象注冊到autoeleasepool赤兴。
規(guī)則
在ARC有效的情況下編譯源代碼妖滔,必須遵守一定的規(guī)則。
- 不能使用 retain/release/retainCount/autorelease
- 不能使用 NSAllocateObject/NSDeallocateObject
- 須遵守內(nèi)存管理的方法命名規(guī)則
- 不要顯式調(diào)用dealloc
- 不能使用區(qū)域(NSZone)
- 對象型變量不能作為C語言結(jié)構(gòu)體(struct/union)的成員
- 顯示轉(zhuǎn)換“id”和“void *”
遵守內(nèi)存管理的方法命名規(guī)則桶良。
在ARC無效時座舍,用于對象生成/持有的方法必須遵守以下的命名規(guī)則。
- alloc
- new
- copy
- mutableCopy
以上述名稱開始的方法在返回對象時陨帆,必須返回給調(diào)用方所應(yīng)當持有的對象曲秉。這在ARC有效時也一樣,返回的對象完全沒有改變疲牵。只是在ARC有效時要追加一條命名規(guī)則承二。
- init
以 init 開始的方法的規(guī)則要比 alloc/new/copy/mutableCopy 更嚴格。該方法必須是實例方法纲爸,并且必須要返回對象亥鸠。返回的對象應(yīng)為id類型或該方法聲明類的對象類型,抑或是該類的超類型或子類型识啦。
屬性
當ARC有效時负蚊,Objective-C類的屬性也會發(fā)生變化。
@property (nonatomic, strong) NSString *name;
當ARC有效時颓哮,以下可作為這種屬性聲明中使用的屬性來用家妆。如表1-3所示。
表1-3 屬性聲明的屬性與所有權(quán)修飾符的對應(yīng)關(guān)系
屬性聲明的屬性 | 所有權(quán)修飾符 |
---|---|
assign | __unsafe_unretained 修飾符 |
copy | __strong 修飾符(但是賦值的是被復制的對象) |
retain | __strong 修飾符 |
strong | __strong 修飾符 |
unsafe_unretained | __unsafe_unretained 修飾符 |
weak | __weak 修飾符 |
assign與weak冕茅,它們都是弱引用聲明類型揩徊,最大的區(qū)別在那呢?
如果用weak聲明的變量在棧中就會自動清空嵌赠,賦值為nil塑荒。
如果用assign聲明的變量在棧中可能不會自動賦值為nil,就會造成野指針錯誤姜挺!
- 修飾變量類型的區(qū)別
weak 只可以修飾對象齿税。如果修飾基本數(shù)據(jù)類型,編譯器會報錯-“Property with ‘weak’ attribute must be of object type”炊豪。
assign 可修飾對象凌箕,和基本數(shù)據(jù)類型拧篮。當需要修飾對象類型時,MRC時代使用unsafe_unretained牵舱。當然串绩,unsafe_unretained也可能產(chǎn)生野指針,所以它名字是"unsafe_”芜壁。- 是否產(chǎn)生野指針的區(qū)別
weak 不會產(chǎn)生野指針問題礁凡。因為weak修飾的對象釋放后(引用計數(shù)器值為0),指針會自動被置nil慧妄,之后再向該對象發(fā)消息也不會崩潰顷牌。 weak是安全的。
assign 如果修飾對象塞淹,會產(chǎn)生野指針問題窟蓝;如果修飾基本數(shù)據(jù)類型則是安全的。修飾的對象釋放后饱普,指針不會自動被置空运挫,此時向?qū)ο蟀l(fā)消息會崩潰。