ARC 概要



三年前,Xcode開發就一直推崇使用ARC內存管理機制, 再往前的歲月裏使用的是MRC,那時候retainrelease隨處可見,顯然MRC已經成爲歷史,着眼當下:

這裏簡要羅列了 ARC 的一些知識點概要,

這是一個學習並存在容錯的文檔翻譯。




Transitioning to ARC Release Notes  

 

 1. 首先介紹一個概念:

    現在的 OS X系統 iOS系統 都是沒有 垃圾回收 的(GC  Garbage Collection)蘋果使用的內存管理的方法是: 應用計數 機制。從原有的MRC 過度到現在更加先進的ARC 制。


 

 2. ARC 使用中感受到最大的好處(如果曾有MRC體驗 will more feel):

    對於果農來說,再也不用費盡心思考慮對象的retain release 操作了,解放出龐大的能量,使得更能夠專注在有趣的code環節

 


 3. 概要一下ARC

    3.1 ARCMRC都是對遵循着相同的內存管理法則,然而ARC更加優秀,它會在編譯的時候(compile time)自動添加一些code來確保對象的必要和生命力。對於其可靠性,(maybe question apple


    3.2 爲了確保編譯器自動生成正確代碼,ARC toll-free bridging(Coare Fundation <-> OC Object)方法做了限制約束;ARC 添加了一些新的對象引用的生命週期修飾符, 和一些屬性聲明。


    3.3 ARC 起用於系統版本: Xcode4.2 OS X v10.7 iOS 5


    3.4 Xcode 更改工程到ARC模式方法:(choose Edit > Convert to Objective-C ARC);另外對於當個文件,可以使用編譯標識來啓動或者取消ARCTarget > Build Phases > Compile Sources:棄用ARC 使用 -fobjc-arc 禁用ARC 使用 -fno-objc-arc標識對應文件即可。

 


 4. ARC中一些硬性規則:

    這些規則都是爲了讓內存管理模式更加可靠,這些規則只在ARC 編譯模式下發生作用,既然是硬性的,如果違背就會即刻生成編譯時報錯。

    4.1 不能實現或調用:retainreleaseretainCount或者autorelease。拓展爲不能用@selector(retain),@selector(relase)等。

        也不能直接調用dealloc函數,dealloc 函數在ARC機制下不需要(也不能、會導致編譯錯誤)調用【super dealloc】,它其實是在編譯時候自動添加到代碼中。對於Core Foundation-syle objects,任然可以使用CFRetainCFRelease


    4.2 不能使用 NSAllocateObject 或者 NSDeallocateObject 使用alloc 穿件對象,運行時會處理好對象的釋放。

    

    4.3 不能在C的結構體重使用 對象指針,與其使用結構體,可以使用OC對象來管理數據。


    4.4 id void * 之間存在差異,id 其實是一個對象結構體指針, Objective-C對象和Core Foundation類型之間需要做一些特別定位處理

        NSMutableArray *colors = [NSMutableArray arrayWithObject:(id)[[UIColor darkGrayColor] CGColor]];

        [colors addObject:(id)[[UIColor lightGrayColor] CGColor]];


    4.5 不能使用NSAutoreleasePool對象,ARC 提供了@autoreleasepool 塊替代,比前者優秀很多。


    4.6 無需再使用 NSZone OC的運行時機制會忽略它們


    4.7 ARC 引入了一些對方法名和屬性命名的約束。不能用 new 開頭的給一個屬性的訪問器命名,除非設置了一個特意指定的getter

        // Won't work:

        @property NSString *newTitle;

        // Works:

        @property (getter=theNewTitle) NSString *newTitle;



 5.  ARC 引入的生命時修飾符(Lifetime Qualifiers

    5.1 屬性修飾(Property Attributes

        關鍵字 weak strong

        下面的聲明方法同義於: @property(retain) MyClass *myObject;//MRC

        @property(strong) MyClass *myObject;//ARC


        下面的聲明方法相似於: @property(assign) MyClass *myObject;//MRC

        @property(weak) MyClass *myObject


        ARC下, stong 是默認的對象屬性類型。

 

    5.2 變量修飾(Variable Qualifiers

        __strong 默認修飾,只要有一個強引用存在,對象就始終是‘alive’的。

        __weak 特別標註不用保留引用對象的alive,當改對象不再存在強引用的時候,弱引用會將至置爲nil

        __unsafe_unretained,不保留引用對象的alive,對象武強引用是也不置爲nil,如果對象釋放,指針將懸垂。

        __autoreleasing

 

        使用方式(ClassName * qualifier variableName)如:

            MyClass * __weak myWeakReference;

            MyClass * __unsafe_unretained myUnsafeReference;


        注意當 __weak 變量實在stack 上的時候:

        NSString * __weak string = [[NSString alloc] initWithFormat:@"First Name: %@", [self firstName]];

        NSLog(@"string: %@", string);

        clang會給出警告:(Assigning retained object to weak variableobject will be released after assignment)

        打印結果是:string: (null)  ???不得解??

    

    5.3 使用修飾符,避免強引用循環(Strong Reference Cycles

        Quote by Linus Torvalds:"Talk is cheap Show me the code":


        As described, instead, you can use a __block qualifier and set the myController variable to nil in the completion handler:


        MyViewController * __block myController = [[MyViewController alloc] init…];

        // ...

        myController.completionHandler =  ^(NSInteger result) {

            [myController dismissViewControllerAnimated:YES completion:nil];

            myController = nil;

        };

        -----------------

        Alternatively, you can use a temporary __weak variable. The following example illustrates a simple implementation:


        MyViewController *myController = [[MyViewController alloc] init…];

        // ...

        MyViewController * __weak weakMyViewController = myController;

        myController.completionHandler =  ^(NSInteger result) {

            [weakMyViewController dismissViewControllerAnimated:YES completion:nil];

        };

        --------------

        For non-trivial cycles, however, you should use:


        MyViewController *myController = [[MyViewController alloc] init…];

        // ...

        MyViewController * __weak weakMyController = myController;

        myController.completionHandler =  ^(NSInteger result) {

            MyViewController *strongMyController = weakMyController;

            if (strongMyController) {

                // ...

                [strongMyController dismissViewControllerAnimated:YES completion:nil];

                // ...

            }

            else {

                // Probably nothing...

            }

        };



 6. ARC 使用心得語法去管理 AutoRelease Pools

    不能直接使用 類:NSAutoreleasePool,可以使用 @autoreleasepool 塊語法,它更加強大。 如下

    @autoreleasepool {

        // Code, such as a loop that creates a large number of temporary objects.

    }

    這個簡單的結構可以讓編譯器合理處理引用計數的狀態。進入時,自動釋放吃就被嵌入(pushed),當正常退出的時候(break,return,goto,fall-through,and so on )自動釋放 池就被彈出,不過如果是意外退出的情況,釋放池不會彈出(popped)。


 7.  outlets 應該使用weak 但是nib文件中一些來至文件的持有者的高層級的對象需要使用strong windowmenu barscustom controller objects a storyboard scene



 8. Stack 變量將被初始化爲nil

    - (void)myMethod {

        NSString *name;

        NSLog(@"name: %@", name);

    }

 

 9. 管理 Toll-Free Bridging

    編譯器不會自動管理Core Foundation 對象的內存。需要直接更具框架的內存管理規則 調用CFRetain CFRelease

    如果需要在OC CF 之間做處理 利用宏定義(objc/runtime.h 或者CF類型的宏(定義在NSObject.h)中。

    __bridge  CF OC 之間指針轉換   武轉換持有關係。

    __bridge_retained / CFBridgingRetain 將一個OC 指針 切換大奧CF指針,並且轉移持有關係,需要自己負責釋放持有對象關係(使用CFRelease

    __bridge_transfer / CFBridgingRelease 將非OC指針 切換爲OC型,並且將持有關係交給ARC

 

 10.dealloc 函數

    因爲ARC 不會自動 malloc/free,不管理CF對象、文件描述符 等的生命週期,所以需要自己寫一個dealloc函數來釋放這些資源。

    完全不用去對一個實例變量進行release,但是需要自己處理一些不遵循ARC的代碼,如可能需要插入[self setDelegate:nil]到系統類中。

    ARC中是不允許對dealloc函數調用[super dealloc]的,應爲在運行時會自動調用這塊代碼。



參考文檔:ARC Release Notes



發佈了25 篇原創文章 · 獲贊 1 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章