Automatic Reference Counting,自動引用計數(shù),即ARC,WWDC2011和iOS5所引入的。ARC是新的LLVM 3.0編譯器的一項特性,使用ARC,解決了手動內(nèi)存管理的麻煩。永遠(yuǎn)不寫retain,release和autorelease三個關(guān)鍵字。
當(dāng)ARC開啟時,編譯器將自動在代碼合適的地方插入retain,release和autorelease。
關(guān)于效率:ARC是Objective-C編譯器的特性,而不是運行時特性或者垃圾回收機制,ARC所做的只不過是在代碼編譯時為你自動在合適的位置插入release或autorelease,就如同之前MRC時你所做的那樣。因此,至少在效率上ARC機制是不會比MRC弱的,而因為可以在最合適的地方完成引用計數(shù)的維護(hù),以及部分優(yōu)化,使用ARC甚至能比MRC取得更高的運行效率。
ARC的基本規(guī)則:只要某個對象被任一strong指針指向,那么它將不會被銷毀。如果對象沒有被任何strong指針指向,那么就將被銷毀。weak類型的指針也可以指向?qū)ο螅遣⒉粫钟性搶ο蟆?/p>
使用ARC以后,不論是strong還是weak類型的指針,都不再會指向一個dealloced的對象,從根源上解決了意外釋放導(dǎo)致的crash。
__weak NSString *str = [[NSString alloc] initWithFormat:…];
NSLog(@"%@",str); //輸出是"(null)"
由于str是weak,它不會持有alloc出來的NSString對象,因此這個對象由于沒有有效的strong指針指向,所以在生成的同時就被銷毀了。如果我們在Xcode中寫了上面的代碼,我們應(yīng)該會得到一個警告,因為無論何時這種情況似乎都是不太可能出現(xiàn)的。你可以把weak換成strong來消除警告,或者直接前面什么都不寫,因為ARC中默認(rèn)的指針類型就是strong。
編譯標(biāo)記:-fno-objc-arc和-fno-objc-arc
除了最頂層的IBOutlet意外,自己寫的outlet都應(yīng)該是weak)。通過加載xib得到的用戶界面,在其從xib文件加載時,就已經(jīng)是view hierarchy的一部分了,而view hierarchy中的指向都是strong的。因此outlet所指向的UI對象不應(yīng)當(dāng)再被hold一次了。將這些outlet寫為weak的最顯而易見的好處是你就不用再viewDidUnload方法中再將這些outlet設(shè)為nil了
總結(jié)一下新加入的property的關(guān)鍵字類型:
strong 和原來的retain比較相似,strong的property將對應(yīng)__strong的指針,它將持有所指向的對象
weak 不持有所指向的對象,而且當(dāng)所指對象銷毀時能將自己置為nil,基本所有的outlet都應(yīng)該用weak
unsafe_unretained 這就是原來的assign。當(dāng)需要支持iOS4時需要用到這個關(guān)鍵字
copy 和原來基本一樣..copy一個對象并且為其創(chuàng)建一個strong指針
assign 對于對象來說應(yīng)該永遠(yuǎn)不用assign了,實在需要的話應(yīng)該用unsafe_unretained代替(基本找不到這種時候,大部分assign應(yīng)該都被weak替代)。但是對于基本類型比如int,float,BOOL這樣的東西,還是要用assign。
那么ARC是為了解決什么問題誕生的呢?這個得追溯到MRC手動內(nèi)存管理時代說起。
MRC下內(nèi)存管理的缺點:
1.當(dāng)我們要釋放一個堆內(nèi)存時,首先要確定指向這個堆空間的指針都被release了。(避免提前釋放)
2.釋放指針指向的堆空間,首先要確定哪些指針指向同一個堆,這些指針只能釋放一次。(MRC下即誰創(chuàng)建,誰釋放,避免重復(fù)釋放)
3.模塊化操作時,對象可能被多個模塊創(chuàng)建和使用,不能確定最后由誰去釋放。
4.多線程操作時,不確定哪個線程最后使用完畢
橋接一般用于Objective-C的對象與Core Foundation中的類對象之間的轉(zhuǎn)換。它實際上是內(nèi)存儲管理權(quán)的移交。因為Objective-C是ARC管理的對象,而Core Foundation不是ARC管理的對象,所以才要特意這樣轉(zhuǎn)換。也就是說,當(dāng)這兩種類型(有ARC管理,沒有ARC管理)在轉(zhuǎn)換時,需要告訴編譯器怎樣處理對象的所有權(quán)。
(1)__bridge:只做類型轉(zhuǎn)換,但是不修改對象(內(nèi)存)管理權(quán)
NSString *string = [NSString stringWithFormat:...];
CFStringRef cfString = (__bridge CFStringRef)string;
說明:__bridge只是單純地執(zhí)行了類型轉(zhuǎn)換,沒有進(jìn)行所有權(quán)的轉(zhuǎn)移,也就是說,當(dāng)string對象被釋放的時候,cfString也不能被使用了。
(2)__bridge_retained /CFBridgingRetain:將Objective-C的對象——>Core Foundation的對象,同時將對象(內(nèi)存)的管理權(quán)交給開發(fā)者,后續(xù)需要使用CFRelease或者相關(guān)方法來釋放對象
NSString *string = [NSString stringWithFormat:...];
CFStringRef cfString = (__bridge_retained CFStringRef)string;
...
CFRelease(cfString); // 由于Core Foundation的對象不屬于ARC的管理范疇,所以需要自己release
說明:__bridge_retained 可以通過轉(zhuǎn)換目標(biāo)處(cfString)的 retain 處理,來使所有權(quán)轉(zhuǎn)移。即使 string 變量被釋放,cfString 還是可以使用具體的對象。只是有一點,由于Core Foundation的對象不屬于ARC的管理范疇,所以需要自己release??梢杂?CFBridgingRetain 替代 __bridge_retained 關(guān)鍵字:
NSString *string = [NSString stringWithFormat:...];
CFStringRef cfString = CFBridgingRetain(string);
...
CFRelease(cfString); // 由于Core Foundation不在ARC管理范圍內(nèi),所以需要主動release
(3)__bridge_transfer/CFBridgingRelease:將Core Foundation的對象——>Objective-C的對象,同時將CF對象(內(nèi)存)的管理權(quán)交給ARC,不需要手動release
CFStringRef cfString = CFStringCreate...();
NSString *string = (__bridge_transfer NSString *)cfString;
…
// CFRelease(cfString); 因為已經(jīng)用 __bridge_transfer 轉(zhuǎn)移了對象的所有權(quán),所以不需要調(diào)用 release
同樣,我們可以使用 CFBridgingRelease() 來代替 __bridge_transfer 關(guān)鍵字:
CFStringRef cfString = CFStringCreate...();
NSString *string = CFBridgingRelease(cfString);