ARC內存管理下的注意事項

ARC不是萬能的,那ARC下哪些疏漏會引發內存泄漏呢?

(1)Block使用不當造成的循環引用:

    ARC下,copy到堆上的block,會強引用進入到該block中的外部變量.這很容易導致循環引用的問題.

    比方說:

    一個VC(這裏指一個controller)中有一個屬性爲model.VC強引用了它.

    VC --> model

    這個model呢,裏面有一個copy屬性的block,該block賦值如下如下.model.demo = ^{

    ......

    };

    如果這個......沒有傳VC進來,還好,不會強引用VC,如果是下面的情況:

    model.demo = ^{

    ......

    [test getValue:self];

    };

    那,直接導致的後果就是,這個model強引用了這個VC.

    model --> VC

    這就造成了一個循環.即使這個VC被pop掉了,垃圾回收機制也無法釋放這個VC了,因爲,它檢測到了這個VC被model強引用了.

    所以,在ARC下面使用block,無論怎樣,你都需要注意這幾點:

    1. 外部對象進入block,請使用__weak修飾後再進入到block中

    2. 不要在block中初始化對象,請在block的外面初始化對象後再進入到block中去

    3. 無論該block是不是copy的,請都當做copy的block來處理

    4. 傳入到堆區block中的對象會被強引用

 

(2)底層Core Foundation對象的內存管理必須手工進行,如:

    CTFontRef fontRef = CTFontCreateWithName((CFStringRef)@"ArialMT",fontSize,NULL);

        //引用計數+1

        CFRetain(fontRef);

        //引用計數-1

        CFRelease(fontRef);

        Core Foundation對象和Objective-c對象的轉化:__bridge關鍵字

        __bridge:只做類型轉換,不修改相關對象的引用計數,原來的CoreFoundation對象在不用時,需要調用CFRElease

        __bridge_retained:類型轉換後,將相關對象的引用計數+1,原來的Core Foundation對象在不用時,需要調用CFRelease

        __bridge_transfer:類型轉換後,將該對象的引用計數交給ARC管理,Core Foundation對象在不用時,不再需要CFRelease

        詳情:

        在開發iOS應用程序時我們有時會用到Core Foundation對象簡稱CF,例如Core Graphics、Core Text,並且我們可能需要將CF對象和OC對象進行互相轉化,我們知道,ARC環境下編譯器不會自動管理CF對象的內存,所以當我們創建了一個CF對象以後就需要我們使用CFRelease將其手動釋放,那麼CF和OC相互轉化的時候該如何管理內存呢?答案就是我們在需要時可以使用__bridge,__bridge_transfer,__bridge_retained,具體介紹和用法如下

        1.__bridge:CF和OC對象轉化時只涉及對象類型不涉及對象所有權的轉化;

        NSURL *url = [[NSURL alloc] initWithString:@"http://www.baidu.com"];

        CFURLRef ref = (CFURLRef)url;

        上面的這段代碼在ARC環境下系統會給出錯誤提示和錯誤修正,修正後如下:

        NSURL *url = [[NSURL alloc] initWithString:@"http://www.baidu.com"];

        CFURLRef ref = (__bridge CFURLRef)url;

        系統爲我們自動添加了__bridge,因爲是OC創建的對象並且在轉換時沒有涉及對象所有權的轉換,所以上面的代碼不需要加CFRelease

 

        2.__bridge_transfer:常用在講CF對象轉換成OC對象時,將CF對象的所有權交給OC對象,此時ARC就能自動管理該內存;(作用同CFBridgingRelease())

 

        3.__bridge_retained:(與__bridge_transfer相反)常用在將OC對象轉換成CF對象時,將OC對象的所有權交給CF對象來管理;(作用同CFBridgingRetain())

        NSURL *url = [[NSURL alloc] initWithString:@"http://www.baidu.com"];

        CFURLRef ref = (__bridge_retained CFURLRef)url;

        CFRelease(ref);

        當使用_bridge_retained標識符以後,代表OC要將對象所有權交給CF對象自己來管理,所以我們要在ref使用完成以後用CFRelease將其手動釋放.

        CFStringRef cfString= CFURLCreateStringByAddingPercentEscapes(

        NULL,

        (__bridge CFStringRef)text,

        NULL,

        CFSTR("!*’();:@&=+$,/?%#[]"), CFStringConvertNSStringEncodingToEncoding(NSUTF8StringEncoding));

        NSString *ocString = (__bridge_transfer CFStringRef)cfString;

        此時OC即獲得了對象的所有權,ARC負責自動釋放該對象,如果我們在結尾加上CFRelease(cfString)純屬畫蛇添足,雖不會崩潰,但是控制檯會打印出該對象被free了兩次

 

有關ARC與MRC的比較好的文章:https://hit-alibaba.github.io/interview/iOS/ObjC-Basic/MM.html

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