iOS-利用Xcode檢測(cè)循環(huán)引用

  • 首先在我們的程序中添加一段循環(huán)引用代碼
NSMutableArray * arr1 = [NSMutableArray array];
NSMutableArray * arr2 = [NSMutableArray array];

[arr1 addObject:arr2];
[arr2 addObject:arr1];

  • 選擇Product->Profile

    image
  • 選擇Leaks,點(diǎn)擊Choose

    image
  • 分析結(jié)果

    image

點(diǎn)擊左上角1位置的紅點(diǎn)開(kāi)始運(yùn)行;
我們會(huì)發(fā)現(xiàn)在2的位置上出現(xiàn)一個(gè)錯(cuò)誤警告;
選中3Leak Checks;
點(diǎn)擊4位置,選擇Cycles&Roots
我們會(huì)看到5的位置上有一條信息,描述是簡(jiǎn)單循環(huán);
選中那條信息,我們可以看到6位置上呈現(xiàn)出循環(huán)引用的圖示,是不是一下就清晰明了了。


我們?cè)賮?lái)看看多個(gè)對(duì)象之間的循環(huán)引用是什么樣子的

NSMutableArray * array1 = [NSMutableArray array];
NSMutableArray * array2 = [NSMutableArray array];
NSMutableArray * array3 = [NSMutableArray array];
NSMutableArray * array4 = [NSMutableArray array];

[array1 addObject:array2];
[array2 addObject:array3];
[array3 addObject:array4];
[array4 addObject:array1];

image

通過(guò)這樣的方式來(lái)監(jiān)測(cè)循環(huán)引用是不是變得很容易方便,也很清晰明了呢

關(guān)于循環(huán)引用

循環(huán)引用的實(shí)質(zhì)是,多個(gè)對(duì)象之間相互強(qiáng)引用,導(dǎo)致不能釋放,讓系統(tǒng)回收。iOS開(kāi)發(fā)中常見(jiàn)的循環(huán)引用主要是由Delegate、NSTimer和block引起。

一、代理(Delegate)

delegate是開(kāi)發(fā)中比較常見(jiàn)到的循環(huán)引用,一般在聲明delegate的時(shí)候,都需要使用弱引用weak或者assign。MRC下,只能用assign,ARC下,最好用weak,因?yàn)閣eak修飾的變量在釋放后,會(huì)自動(dòng)指向nil,防止出現(xiàn)野指針。

二、定時(shí)器(NSTimer)

在控制器(Controller)內(nèi),創(chuàng)建NSTimer實(shí)例作為其屬性,由于定時(shí)器創(chuàng)建后,也會(huì)強(qiáng)引用該控制器對(duì)象,那么該控制器對(duì)象和定時(shí)器對(duì)象就相互循環(huán)引用了。
要解決該循環(huán)引用,可以手動(dòng)斷開(kāi):
如果是不重復(fù)的NSTimer對(duì)象,在回調(diào)方法里將其invalidate并置為nil即可。
如果是重復(fù)的NSTimer對(duì)象,在適當(dāng)位置將其invalidate并置為nil即可。

三、block

示例:

@property (nonatomic, copy) dispatch_block_t testBlock;
@property (nonatomic, copy) NSString *testString;

- (void)test {
    self.testBlock = ^() {
        NSLog(@"%@", self.testString);
    };
}

此時(shí)編譯器如出現(xiàn)循環(huán)引用的警告??"Capturing 'self' strongly in this block is likely to lead to a retain cycle"。由于block會(huì)對(duì)block內(nèi)的對(duì)象進(jìn)行持有操作,就相當(dāng)于持有了其中的對(duì)象,而如果此時(shí)block中的對(duì)象又持有了該block,則會(huì)造成循環(huán)引用。
解決方法就是使用__weak修飾self:

- (void)test {
    __weak typeof(self) weakSelf = self;
    self.testBlock = ^() {
        NSLog(@"%@", weakSelf.testString);
    };
}

并不是所有的block都會(huì)造成循環(huán)引用,只有被強(qiáng)引用了的block才會(huì)產(chǎn)生循環(huán)引用,例如:dispatch_async(dispatch_get_main_queue(), ^{})[UIView animateWithDuration:1 animations:^{}]這些系統(tǒng)方法等,或者block并不是其屬性而是臨時(shí)變量,即棧block。
還有一種場(chǎng)景,在block執(zhí)行開(kāi)始時(shí),self對(duì)象還未被釋放,而執(zhí)行過(guò)程中,self被釋放了,由于是用weak修飾的,那么weakSelf也被釋放了,此時(shí)在block內(nèi)訪問(wèn)weakSelf,就可能會(huì)發(fā)生錯(cuò)誤(向nil對(duì)象發(fā)消息并不會(huì)崩潰,但是沒(méi)有效果)。
對(duì)于這種場(chǎng)景,應(yīng)該再block中對(duì)對(duì)象使用__strong修飾,使得在block期間對(duì)對(duì)象持有,block執(zhí)行結(jié)束后,解除其持有。示例如下:

__weak typeof(self) weakSelf = self;
self.testBlock = ^() {
    __strong __typeof(self) strongSelf = weakSelf;
    [strongSelf testMethod];
};

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 首先在我們的程序中添加一段循環(huán)引用代碼 選擇Product->Profile 選擇Leaks,點(diǎn)擊Choose 分...
    JerryLMJ閱讀 9,651評(píng)論 1 9
  • 直到 2013 年左右,蘋果認(rèn)為 ARC 技術(shù)足夠成熟,直接將 macOS(當(dāng)時(shí)叫 OS X)上的垃圾回收機(jī)制廢棄...
    guoguojianshu閱讀 550評(píng)論 0 0
  • 做這個(gè)的初心是希望能鞏固自己的基礎(chǔ)知識(shí),也通過(guò)這種方式檢查自己知識(shí)的缺失點(diǎn)。目前還不完善,后續(xù)會(huì)根據(jù)時(shí)間不斷更正和...
    lp_lp閱讀 37,376評(píng)論 7 147
  • UIKit 1.UIView 和 CALayer 是什么關(guān)系? UIView 繼承 UIResponder,而 U...
    Sephiroth_Ma閱讀 2,451評(píng)論 0 25
  • 目錄 1.用什么方式判斷gif/png圖片的? 取出圖片數(shù)據(jù)的第一個(gè)字節(jié), 就可以判斷出圖片的真實(shí)類型 使用方法 ...
    勇敢的_心_閱讀 923評(píng)論 0 2

友情鏈接更多精彩內(nèi)容