探秘ios中block的循環(huán)引用問題

hello,小伙伴們!
ios中自從引入了block,代理就在慢慢淡出我們的視野,那么block的使用大家都了解嗎?它的循環(huán)引用機制大家都了解嗎?接下來我們就來聊聊這個話題.

一,介紹下簡單block的寫法.

//a,typedef 定義下的block寫法
typedef void(^cusBlock)();
@property (copy , nonatomic)  cusBlock block;

//b,直接屬性定義下的block寫法
@property (copy , nonatomic)  void (^customBlock)();
//還有很多寫法,大家可以參考其它牛人的寫法,這里就不做介紹了.

二,執(zhí)行block代碼塊(customBlock)

 self.customBlock = ^(){
        self.name = @"lili";
        NSLog(@"執(zhí)行了block塊的方法");
        
    }
    }
touchesBegan后
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    
    if (self.customBlock) {
        self.customBlock();
    }
    
}
輸出結(jié)果:2017-02-27 19:30:46.815 text[15115:303861] 執(zhí)行了block塊的方法

三,block循環(huán)引用的結(jié)論

//先說結(jié)論,后面再來分析
 如果 [block內(nèi)部] 訪問了 [外部強引用] 對象A ,那么 [block內(nèi)部] 會自動產(chǎn)生一個 [強引用引用] 對象A;

 如果 [block內(nèi)部] 訪問了 [外部弱引用] 對象A ,那么 [block內(nèi)部] 會自動產(chǎn)生一個 [弱引用引用] 對象A;

四,分析循環(huán)引用,驗證結(jié)論

a,上述代碼強引用的示意圖

block強引用示意圖.png

這樣系統(tǒng)會拋出一個??錯誤

強引用警告示意圖.png

執(zhí)行完block代碼后

block執(zhí)行完成后強引用示意圖.png

這個提示告訴我們,block內(nèi)部出現(xiàn)了循環(huán)引用(有強迫癥的最好解決下,免得越積越多).

b,解決辦法,大家都知道的弱引用就可以完美的解決問題了.示意圖如下

block弱引用示意圖.png

c,特殊情況

@interface BLPerson : NSObject
@property(copy, nonatomic) NSString *name;
@property (copy , nonatomic)  void (^customBlock)();
@end
#import "BLPerson.h"

- (void)viewDidLoad{
   [super viewDidLoad];
   self.view.backgroundColor = [UIColor whiteColor];
   BLPerson *p = [[BLPerson alloc]init];
   __weak typeof(p)weakp = p;
   p.name = @"jack";
   p.customBlock = ^(){
       dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
           weakp.name = @"lili";
           NSLog(@"%@==執(zhí)行了block塊的方法",weakp.name);
       });
   };
   if (p.customBlock) {
       p.customBlock();
   }
}

運行結(jié)果:2017-02-28 11:17:23.519 text[4118:80908] (null)==執(zhí)行了block塊的方法
weakp.name =null,這是為什么了,在block里面我明明已經(jīng)將 weakp.name = @"lili"賦值了啊.

經(jīng)過分析這是因為,在執(zhí)行dispatch_after這個block中代碼的時候,由于weakp是弱引用,在這個時間差之間weakp已經(jīng)被釋放了,weakp為nil,意味著nil.name就沒意義了.

解決辦法:在customBlock里面用一個強引用在引用weakp就行了;

 p.customBlock = ^(){ 
        BLPerson *p1 = weakp;
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            p1.name = @"lili";
            NSLog(@"%@==執(zhí)行了block塊的方法",p1.name);
        });
    };
輸出結(jié)果:2017-02-28 11:26:41.679 text[4280:84156] lili==執(zhí)行了block塊的方法;這個時候P1.name是有值的;
ps:在block里面定義的屬性是不會造成強引用的;

本章總結(jié):
請大家牢記這兩個結(jié)論,理解透了沒有block會阻礙你前進的步伐.

如果 [block內(nèi)部] 訪問了 [外部強引用] 對象A ,那么 [block內(nèi)部] 會自動產(chǎn)生一個 [強引用引用] 對象A;

 如果 [block內(nèi)部] 訪問了 [外部弱引用] 對象A ,那么 [block內(nèi)部] 會自動產(chǎn)生一個 [弱引用引用] 對象A;

建議以后block里面如果沒有特殊要求,建議都寫成弱引用,避免造成自己都發(fā)現(xiàn)不了的bug.本文,如有誤之處,請大家多多指教,我一定虛心學(xué)習(xí),希望同大家共同進步.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容