国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

BLOCK循環引用

2019-11-09 18:53:57
字體:
來源:轉載
供稿:網友

循環引用的原因

眾所周知,ARC下用block會產生循環引用的問題,造成泄露的原因是啥呢?

最簡單的例子,如下面代碼:

123[self.teacher requestData:^(NSData *data) {    self.name = @"case";}];

此種情況是最常見的循環引用導致的內存泄露了,在這里,self強引用了teacher, teacher又強引用了一個block,而該block在回調時又調用了self,會導致該block又強引用了self,造成了一個保留環,最終導致self無法釋放。

self -> teacher -> block -> self

一般性的解決方案

12345__weak typeof(self) weakSelf = self;    [self.teacher requestData:^(NSData *data) {        typeof(weakSelf) strongSelf = weakSelf;       strongSelf.name = @"case";    }];

通過__weak的修飾,先把self弱引用(默認是強引用,實際上self是有個隱藏的__strong修飾的),然后在block回調里用weakSelf,這樣就會打破保留環,從而避免了循環引用,如下:

self -> teacher -> block -> weakSelf

PS:一般會在block回調里再強引用一下weakSelf(typeof(weakSelf) strongSelf = weakSelf;),因為__weak修飾的都是存在棧內,可能隨時會被系統釋放,造成后面調用weakSelf時weakSelf可能已經是nil了,后面用weakSelf調用任何代碼都是無效的。

通過demo證明哪些情況下有泄漏

雖然說用block時會產生循環引用,但并不是所有情況下都會有內存泄露的問題,看個demo。

先發demo地址:https://github.com/yuedong56/BlockRetainCycleDemo

進入demo,有個Button,點擊Button push到SecondViewController,

SecondViewController中有六種情況的Button,每點一個Button會觸發一個block,

點擊返回,回到首頁,如果執行了dealloc,證明SecondViewController正常釋放,否則,證明內存泄露了。

01.png

下面只貼demo里的關鍵代碼了,全的代碼請自行下載demo,大家看下面的六種情況,是否會產生內存泄漏。

1234567//情況一- (void)case1 {    NSLog(@"case 1 Click");    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{        self.name = @"case 1";    });}
123456789//情況二- (void)case2 {    NSLog(@"case 2 Click");    __weak typeof(self) weakSelf = self;    [self.teacher requestData:^(NSData *data) {        typeof(weakSelf) strongSelf = weakSelf;       strongSelf.name = @"case 2";    }];}
1234567//情況三- (void)case3 {    NSLog(@"case 3 Click");    [self.teacher requestData:^(NSData *data) {        self.name = @"case 3";    }];}
12345678//情況四- (void)case4 {    NSLog(@"case 4 Click");    [self.teacher requestData:^(NSData *data) {        self.name = @"case 4";        self.teacher = nil;    }];}
12345678//情況五- (void)case5 {    NSLog(@"case 5 Click");    Teacher *t = [[Teacher alloc] init];    [t requestData:^(NSData *data) {        self.name = @"case 5";    }];}
1234567891011//情況六- (void)case6 {    NSLog(@"case 6 Click");    [self.teacher callCase6BlackEvent];    self.teacher.case6Block = ^(NSData *data) {        self.name = @"case 6";        //下面兩句代碼任選其一        self.teacher = nil;//        self.teacher.case6Block = nil;    };}

分析

情況一:執行了dealloc,不泄露,此情況雖然是block,但未形成保留環block -> self

情況二:執行了dealloc,不泄露,此情況就是內存泄漏后的一般處理了 self ->teacher ->block ->strongSelf,后面那個strongSelf和原來的self并沒有直接關系,因為strongSelf是通過weakSelf得來的,而weakSelf又沒有強引用原來的self

情況三:未執行dealloc,內存泄漏,此情況就是最典型的循環引用了,形成保留環無法釋放,self ->teacher ->block ->self

情況四:執行了dealloc,不泄露,雖然也是保留環,但通過最后一句,使self不再強引用teacher,打破了保留環

情況五:執行了dealloc,不泄露,未形成保留環 t ->block ->self

情況六:執行了dealloc,不泄露,最后兩句代碼任選其一即可防止內存泄漏,self.teacher 或者 case6Block 置為空都可以打破 retain cycle

PS: 雖然情況四、情況六的寫法都可以防止內存泄漏,不過為了統一,個人建議最好還是按照普通寫法即情況二的寫法。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 枞阳县| 阜新市| 阜康市| 鄂伦春自治旗| 沙湾县| 府谷县| 佛山市| 大关县| 仙居县| 和静县| 祁门县| 金沙县| 曲沃县| 武汉市| 柳州市| 新和县| 白沙| 山阳县| 屏边| 长武县| 林芝县| 平果县| 浦江县| 仙居县| 九寨沟县| 曲靖市| 虎林市| 宜州市| 鹿泉市| 浠水县| 衡山县| 芷江| 突泉县| 中牟县| 深水埗区| 温泉县| 双柏县| 天门市| 海晏县| 清镇市| 和龙市|