什麼是ARC?
官方給出的解釋是:Automatic Reference Counting (ARC) is a compiler feature that provides automatic memory management of Objective-C objects. Rather than having to think about retain and release operations, ARC allows you to concentrate on the interesting code, the object graphs, and the relationships between objects in your application.
自動引用計數是一種編譯器特性,提供對象的自動內存管理。ARC使得你能夠專一於你的應用中的代碼,UI以及對象之間的關係而不須要去關心使用retain、release去進行繁冗的內存管理。html
ARC經過增長編譯時代碼確保對象按需存在,按需釋放。概念上來講,它與手動引用計數(MRC)聽從一樣的規則:爲你添加正確適當的內存管理代碼。爲了確保編譯器生成正確的代碼,ARC限制了你可使用的方法和你使用toll-tree bridging的方式。Toll-free bridging,簡稱爲TFB,是一種容許某些ObjC類與其對應的CoreFoundation類之間能夠互換使用的機制。關於Toll-free bridging能夠搜索官方文檔,這裏給出一篇推薦博文:清風徐來,水波不興。程序員
ARC的支持:Xcode4.2以上,OS X v10.7以上,IOS5以上。能夠參考官方原句:ARC is supported in Xcode 4.2 for OS X v10.6 and v10.7 (64-bit applications) and for iOS4 and iOS5.Weak references are not supported in OS X v10.6 and iOS 4.
編程
ARC與MRC的區別及編程方式
MRC : Manual Reference Counting。使用retain來增長內存的引用計數,release來減小引用計數,autorelease來加入自動釋放池等等。
ARC : Automatic Reference Counting。自動引用計數,毫不能再出現以上的三個關鍵字,實際上Xcode也會報錯。app
使用ARC須要遵循的新規則:
爲了正確的工做,ARC規定了一些其餘編譯模式沒有的新規則。這些規則旨在提供一個徹底可信的內存管理模型,在一些狀況下,他們僅執行最佳實踐,而另外一些狀況下,他們簡化你的代碼或者明顯的告知你不須要處理內存管理。若是你違反了這些規則,你會獲得一個明顯的編譯時錯誤,而不是一個微小的錯誤可是在運行時卻有可能成爲一個大問題,問題能夠及早的暴漏出來,而不是在程序有bug的時候再去苦苦的找bug,因此說ARC簡直是程序員的福音。相比之下,仍是遵照下面的這些規則比較簡單:
ide
1 . 不能顯式調用dealloc,retain,release,retainCount,autorelease,或者是使用@selector(retain),@selector(release)等等。可是你能夠若是你須要釋放一些資源而不是釋放實例變量時,你能夠實現dealloc,在dealloc函數裏面去完成這些工做,可是記住,不要去調用,由於編譯器會幫你作的。同時,dealloc函數裏也不要去調用super dealloa,這也是編譯器的工做。可是你可能須要在系統類和其餘未使用ARC的代碼中調用[systemClassInstance setDelegate:nil] ,同時你也須要使用CFRetain,CFRelease和其餘CoreFoundation對象的相關方法。理解了Toll-free bridging你或許會清楚這個問題。函數
2 . 不能使用NSAllocateObject或者NSDeallocateObject。使用alloc建立對象,系統在運行時會關注對象的生存週期並在適當的時候釋放他。ui
3 . 不能在C結構體中使用對象指針。若是你要使用結構體,還不如直接創建一個Objective-C對象來管理數據。spa
4 . id與void *之間不能隨意的轉換。你必須使用特定的類型轉換告訴編譯器對象的生命週期,在Objective-C對象與做爲函數傳入參數的CoreFoundation對象之間你須要作這樣的轉換。翻譯
5 . 不能使用NSAutoreleasePool自動釋放池。ARC提供@autoreleasepool代替,而且比NSAutoreleasePool更高效。設計
6 . 不能使用內存區(memmory zons)。再也沒有必要使用NSZone,由於現代的Objective-C運行時會忽略它。
7 . 不能以new爲開頭去命名一個訪問器,這意味着你不能聲明一個以new開頭的property,除非你附給他一個不一樣名字的getter:
@property NSString *newTitle; //錯誤的
@property (getter=theNewTitle) NSString *newTitle; //正確的
ARC的編程方式
ARC引入了新的對象生命週期修飾符和弱引用。weak reference弱引用不會增長它所指向的對象的引用計數,並且當它所指向的對象引用計數變爲0時會自動的變成nil,這樣咱們不用擔憂會指向已經釋放的內存,EXC_BAD_ACCESS錯誤也會減小不少。你也能夠充分使用這些修飾符來管理你的程序中的對象,好比說,ARC沒法避免強循環引用,可是你能夠巧妙的使用weak修飾符來確保你的程序不會有循環引用。
weak和strong是新引入的屬性修飾符,例子以下:
1 @property(strong) MyClass *myObject; //強引用,同retain 2 @property(weak) MyClass *myObject; //弱引用,同assign,當所指向的對象被釋放後被自動的置爲nil
在ARC的工程中,strong是對象的默認屬性,可是爲了不歧義最好仍是顯式的指明。
變量修飾符:
上面介紹了屬性修飾符,下面來看看這幾款變量修飾符。const你必定使用過,相似的變量修飾符還有這些:
__strong
__weak
__unsafe_unretained
__autoreleasing
__strong:缺省的修飾符,當對象有strong指針指向他時,他是不被釋放的,alive。
__weak:保留對對象的弱引用指針,不增長引用計數,所以也對對象的生命週期沒有保障,當所指向的對象被釋放後自動置爲nil。
__unsafe_unretained:保留對象的弱引用指針,當所指向的對象被釋放後,該指針不會被置爲nil,變成野指針。
__autoreleasing:修飾以引用(id *)傳入的參數,而且當return後會被自動釋放。主要用於引用傳入參數。
變量修飾符的使用格式:
ClassName * qualifier variableName;
例如:
MyClass * __weak myWeakReference; MyClass * __unsafe_unretained myUnsafeReference;
雖然說編譯器很偉大但偶爾也會小粗心一下,例以下面的錯誤就不會被報錯,只是小警告,因此不要忽略警告哦~下面的例子是錯誤示例:
NSString * __weak string = [[NSString alloc] initWithFormat:@"First Name: %@", [self firstName]]; NSLog(@"string: %@", string);
雖然string在剛建立並初始化完成後使用,可是並無一個強指針指向該對象,所以他一初始化完成就因爲引用計數爲0被釋放了。結果輸出的是null,緣由你懂的,上面說過三遍。
經過引用傳入的對象也須要注意,下面的例子是正確的:
-(BOOL)performOperationWithError:(NSError * __autoreleasing *)error;
NSError *error; BOOL OK = [myObject performOperationWithError:&error]; if (!OK) { //use }
編譯器會將代碼補全爲以下:
1 NSError * __strong error; 2 NSError * __autoreleasing tmp = error; 3 BOOL OK = [myObject performOperationWithError:&tmp]; 4 error = tmp; 5 if (!OK) { 6 //use 7 }
以__autoreleasing聲明參數實際上是告訴ARC編譯器,這個函數沒有這個對象的擁有權,因此在函數裏面的read和write該引用所指向的對象時,就將它放到自動釋放池吧,return後就釋放掉,固然這些是編譯器作的事。官方文檔告訴咱們:傳入的本地變量爲__strong(默認的)與形參__autoreleasing不匹配致使了編譯器會生成一個臨時變量tmp,你能夠像以上這樣作,聲明參數爲__autoreleasing,同時也能夠經過將參數聲明爲id __strong *來得到__strong變量的地址。(如今尚沒有想清楚這兩種有什麼區別)
ARC中如何避免循環引用?
你可使用對象的生命週期修飾符來避免強引用循環而致使的互相引用內存不能被釋放,從而形成內存泄露。例如,你能夠設計一個父子對象圖,父對象對子對象能夠強引用strong,同時子對象對父對象的引用爲弱類型的引用weak。
巧妙的使用weak弱引用是避免循環引用的良藥,這就是一般爲何delegate爲弱類型的緣由。另外最容易循環引用的一塊就是block內對自身的屬性引用,這又是另一塊很重要的問題,將在後續的博客中單獨做爲一篇來說解。
如何將設置工程爲ARC?
1.新建ARC工程
新的編譯器新建的工程默認支持ARC,查看Objective-C Automatic Reference Counting選項,YES表示支持ARC。
2.將舊MRC工程轉化爲ARC
(1)首先查看編譯器是否支持,若是不支持選擇編譯器或者升級編譯器,記住ARC是LLVM 3.0及之後的新特性,以前的編譯器不支持,若是你的Compiler選項還在以前,那趕忙升級Xcode吧,不然新時代已經不適合你咯~按照下面的圖示選擇便可,個人Xcode是5.0的,編譯器也是5.0。
(2)一樣是在Build Settings裏面,將Objective-C Automatic Reference Counting選項改成YES,以下:
(3)run一下工程吧,不少錯誤吧,一個一個改正吧~按照咱們前面提到的ARC的規則,將一些retain,release等相關MRC字段都改成ARC規則的,將一些property屬性,retain改成strong,assign改成weak,不能顯示調用dealloc函數等等,記住一些基礎類型如BOOL等仍是assign。對於一個小工程來講手動修改很容易,可是工程很大就比較費腦筋了,幸好偉大的Xcode提供了自動轉換到ARC的功能。具體就再也不細說,能夠參考這個牛人的博客裏面的例子:人淡如菊,講的已經很是詳細。同時也會有些非ARC的第三方庫那就直接將庫設置編譯屬性爲非ARC吧,不要去修改庫了。另外,Core Foundation的一些東西也會牽扯到橋接的內容,後續博客再詳細介紹。
3.設置ARC工程中兼容MRC的文件
在工程的Build Phases中的Compile Sources選項中找到對應的.m文件,將其Compiler Flags設置爲-fobjc-arc,這樣單個文件就支持ARC了。而若是ARC的工程中裏,想要設置某個單個文件不支持ARC,一樣的操做步驟,將其Compiler Flags設置爲-fno-objc-arc。
一些推薦閱讀的內容:
官方ARC文檔(英文的,本篇博客大部分都翻譯於此,另外也有些ARC相關的重要內容,後續我會繼續翻譯)
OneV's Den的這篇文章(很詳細,耐着性子看完會頗有收穫)
Clang 3.0 Document (超長哦,是我翻譯的目標)
聲明:本博客所有本身手動整理,翻譯了官方博客,而且用本身的話整理了一些內容,若有問題,請在下面回覆,謝謝!