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

首頁 > 學院 > 開發(fā)設(shè)計 > 正文

BLOCK循環(huán)引用

2019-11-09 18:02:49
字體:
供稿:網(wǎng)友

循環(huán)引用的原因

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

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

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

此種情況是最常見的循環(huán)引用導致的內(nèi)存泄露了,在這里,self強引用了teacher, teacher又強引用了一個block,而該block在回調(diào)時又調(diào)用了self,會導致該block又強引用了self,造成了一個保留環(huán),最終導致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回調(diào)里用weakSelf,這樣就會打破保留環(huán),從而避免了循環(huán)引用,如下:

self -> teacher -> block -> weakSelf

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

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

雖然說用block時會產(chǎn)生循環(huán)引用,但并不是所有情況下都會有內(nèi)存泄露的問題,看個demo。

先發(fā)demo地址:https://github.com/yuedong56/BlockRetainCycleDemo

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

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

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

01.png

下面只貼demo里的關(guān)鍵代碼了,全的代碼請自行下載demo,大家看下面的六種情況,是否會產(chǎn)生內(nèi)存泄漏。

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;    };}

分析

情況一:執(zhí)行了dealloc,不泄露,此情況雖然是block,但未形成保留環(huán)block -> self

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

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

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

情況五:執(zhí)行了dealloc,不泄露,未形成保留環(huán) t ->block ->self

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

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


發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 出国| 贵港市| 新乐市| 隆尧县| 平定县| 车致| 讷河市| 大理市| 共和县| 霍邱县| 始兴县| 新乡市| 宜宾县| 许昌县| 晋州市| 永善县| 松滋市| 太康县| 宁安市| 廊坊市| 昌江| 潮安县| 阿拉善盟| 崇阳县| 扬中市| 永靖县| 蓬莱市| 酒泉市| 九寨沟县| 鄂托克前旗| 安平县| 太原市| 旌德县| 黎川县| 正定县| 米脂县| 夏津县| 稷山县| 庆安县| 龙井市| 惠安县|