iOS __weak、__block使用

weixin_34054866發表於2017-12-11

總之這一切其實就是為了防止迴圈引用,下面結合網路上各位大牛的分析精華分析分析

block對於其變數都會形成強引用(retain),對於self也會形成強引用(retain) ,而如果self本身對block也是強引用的話,就會形成 強引用 迴圈,無法釋放——造成記憶體洩露
什麼是迴圈引用:物件A持有物件B,物件B持有物件A,相互持有,最終導致兩個物件都不能釋放。

迴圈引用場景:
1、block在主函式體用到了self / self.變數 / [self 方法],意味著:block對self 進行持有操作;
2、self宣告瞭屬性變數block,block用copy來修飾,意味著:self對block進行持有操作,會造成迴圈引用;
例如下圖,現在這樣寫Xcode直接就會有警告出來告訴你這裡貌似retain cycle了啊!!


668798-dbd1dc504450175d.png
迴圈引用例子

假如我想在block裡面改變區域性變數的值或者使用區域性變數,如下圖這麼寫Xcode直接報錯 而且給出瞭解決方法提示出來了 這點還挺機智的,那麼我們使用__block修飾之後,再次在block裡面使用,就不會出問題了,完美。


668798-1d9d9a6f77f7bf95.png
解決


668798-c53e98fd6422cee5.png
使用區域性變數.png
在使用block的地方:
__block typeof(self) bself = self;          // 適用MRC模式,
__block NSString *tempStr = @"abc";
__block int a = 0; //當修飾變數時,表示這個變數值能在block中被修改
__weak typeof(self) weakself = self;     // 適用ARC模式

關於——Block在MRC和ARC模式的區別
1)__block在MRC下有兩個作用
允許在Block中訪問和修改區域性變數
禁止Block對所引用的物件進行隱式retain操作

2)__block在ARC下只有一個作用
允許在Block中訪問和修改區域性變數

什麼時候在 block 中不需要使用 weakSelf???

  • 大部分GCD方法,因為self並沒有對GCD的block進行持有,沒有形成迴圈引用。目前我還沒碰到使用GCD導致迴圈引用的場景,如果某種場景self對GCD的block進行了持有,則才有可能造成迴圈引用。

dispatch_async(dispatch_get_main_queue(), ^{
[self doSomething];
});

  • 大部分動畫效果,當動畫結束時,UIView 會結束持有這個 block,block 物件就會釋放掉,從而 block 會釋放掉對於 self 的持有。整個記憶體引用關係被解除。

[UIView animateWithDuration:0.2 animations:^{
self.alpha = 1;
}];

  • block並不是物件的屬性 / 變數,而是方法的引數 / 臨時變數,這裡因為block只是一個臨時變數,self並沒有對其持有,所以沒有造成迴圈引用

.- (void) testWithBlock:(void(^)())block {
block();
}

  • 還有一種情況,block屬於Person物件,在另一個類裡面使用的時候沒有構成互相持有,這時候也不需要weakSelf。

  • 使用GCD的時候,這麼寫其實是錯誤的,並不是見到block就要為了防止迴圈引用而使用weakSelf,像下面這種寫法,就是錯誤的:

__weak typeof(self) weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf doSomething];
});

因為將block作為引數傳給dispatch_async時,系統會將block拷貝到堆上,而且block會持有block中用到的物件,因為dispatch_async並不知道block中物件會在什麼時候被釋放,為了確保系統排程執行block中的任務時其物件沒有被意外釋放掉,dispatch_async必須自己retain一次物件(即self),任務完成後再release物件(即self)。但這裡使用__weak,使dispatch_async沒有增加self的引用計數,這使得在系統在排程執行block之前,self可能已被銷燬,但系統並不知道這個情況,導致block執行時訪問已經被釋放的self,而達不到預期的結果。

總結
1 在 Block 內如果需要訪問 self 的方法、變數,建議使用 weakSelf。
2 如果在 Block 內需要多次 訪問 self,則需要使用 strongSelf。

相關文章