第一篇文章 Block深層剖析(一)介紹了Block的一些基礎(chǔ)概念和用法。
第二篇文章 Block深層剖析(二)分析了最簡(jiǎn)單的Block源碼。
第三篇文章 Block深層剖析(三) 介紹了Block截獲的相關(guān)特點(diǎn)和__block說(shuō)明符。
第四篇文章 Block深層剖析(四) 介紹了Block存儲(chǔ)域和__block存儲(chǔ)域。
這篇文章會(huì)介紹Block的循環(huán)引用問(wèn)題。
1.Block的循環(huán)引用
首先舉一個(gè)產(chǎn)生循環(huán)引用的例子
typedef void(^blockType) (void);
@interface MyBlockObject : NSObject
@property (nonatomic, copy) blockType blockObject;
@end
@implementation MyBlockObject
- (instancetype)init{
if (self = [super init]) {
_blockObject = ^{
NSLog(@"self = %@",self);
};
}
return self;
}
- (void)dealloc{
NSLog(@"dealloc");
}
@end
MyBlockObject * blkObj = [[MyBlockObject alloc]init];
對(duì)象blkObj持有Block變量_blockObject,同時(shí)_blockObject變量持有對(duì)象blkObj。這就造成了循環(huán)引用,會(huì)導(dǎo)致blkObj對(duì)象一直不會(huì)被釋放,造成內(nèi)存泄漏。
解決方法:
(1) __block斷環(huán)
在使用完blkSelf后 將它置空,斷開(kāi)其中一環(huán)。但這樣做有一個(gè)弊端在沒(méi)有調(diào)用block前,這個(gè)循環(huán)引用一直存在,造成內(nèi)存泄漏。
這種方式也有優(yōu)點(diǎn):
- 通過(guò)__block變量可控制對(duì)象的持有期間
__block MyBlockObject * blkSelf = self;
_blockObject = ^{
NSLog(@"self = %@",blkSelf);
blkSelf = nil;
};
MyBlockObject * blkObj = [[MyBlockObject alloc]init];
blkObj.blockObject();
(2)__weak弱引用
__weak typeof(self) weakself = self;
_blockObject = ^{
NSLog(@"self = %@",weakself);
};
在使用__weak時(shí)要配合__strong使用
對(duì)比下面 兩個(gè)代碼
- 不使用__strong
MyBlockObject * blkObj = [[MyBlockObject alloc] init];
__weak MyBlockObject *weakBlkObj = blkObj;
blkObj.blockObject = ^(){
NSLog(@"weakBlkObj對(duì)象地址:%@",weakBlkObj);
dispatch_async(dispatch_queue_create(DISPATCH_QUEUE_PRIORITY_DEFAULT, NULL), ^{
int num = 1000000;
while (num -- > 0) { }
NSLog(@"耗時(shí)的任務(wù) 結(jié)束 weakBlkObj對(duì)象地址:%@",weakBlkObj);
});
};
blkObj.blockObject();
打印結(jié)果
weakBlkObj對(duì)象地址:<MyBlockObject: 0x600001d5c2d0>
dealloc
耗時(shí)的任務(wù) 結(jié)束 weakBlkObj對(duì)象地址:(null)
- 使用__strong
MyBlockObject * blkObj = [[MyBlockObject alloc] init];
__weak MyBlockObject *weakBlkObj = blkObj;
blkObj.blockObject = ^(){
NSLog(@"weakBlkObj對(duì)象地址:%@",weakBlkObj);
__strong MyBlockObject *strongBlkObj = weakBlkObj;
dispatch_async(dispatch_queue_create(DISPATCH_QUEUE_PRIORITY_DEFAULT, NULL), ^{
int num = 1000000;
while (num -- > 0) {}
NSLog(@"耗時(shí)的任務(wù) 結(jié)束 strongBlkObj對(duì)象地址:%@",strongBlkObj);
});
};
blkObj.blockObject();
打印結(jié)果
weakBlkObj對(duì)象地址:<MyBlockObject: 0x600003160440>
耗時(shí)的任務(wù) 結(jié)束 strongBlkObj對(duì)象地址:<MyBlockObject: 0x600003160440>
dealloc
總結(jié)不使用__strong時(shí),在耗時(shí)操作結(jié)束之后 weakBlkObj被釋放,這時(shí)再使用weakBlkObj對(duì)象可能會(huì)造成異常,所以需要用__strong強(qiáng)引用weakBlkObj對(duì)象使其在耗時(shí)操作之后再釋放。