简谈造成循环引用的原因以及处理办法
前段时间写项目的时候我在每个block使用前我都加了一个__weak来修饰用@property描述的属性,项目写的差不多了回头来反思,总觉得这种写太麻烦了,回想起来,还是由于自己对于循环引用造成的原因理解不够透彻,才导致做了很多的无用功。
废话不多说,上代码了 :
/*
// way 1 获取数据
model = [[MoveModel alloc] init];
model.successBlock = ^(id returnBlock) {
NSArray *array = (NSArray *)returnBlock;
_dataArray = array;
[mainTableview reloadData];
};
[model getMoveData];
*/
/*
// way 2 获取数据
[MoveModel GetDataSuccessBlock:^(id returnValues) {
NSArray *array = (NSArray *)returnValues;
_dataArray = array;
[mainTableview reloadData];
}];
*/
这两种方式都是从别的类中获取数据的方法,way1采用的是属性block,way2采用的是参数block,而block内部的数据处理方式是一样的,但事实是way1造成了循环引用,而way2却没有。---不要问我怎么知道的,我就是知道~~
block在iOS开发中视为对象因此生命周期会一直等到持有者的生命周期结束了才会结束另外一方面
由于block的捕获变量的机制使得block的对象也可能被block持有从而造成循环引用造成内存泄露
第一种情况就是这样的,block在控制器内部实现的,它的持有者是控制器本身,而在block内部又调用了_dataArray,它又持有了控制器。最终内存泄露了。
解决办法: 1:声明 weakSelf
typeof(self) __weak weakSelf = self
block内部的_dataArray 换成weakSelf.dataArray
但是这样又会产生另外一种特殊情况,就是在回调block的时候,block中的对象很有可能已经释放了,找不到对象会导致crash。这种情况比较少见,但是需要防范。
2 在block内部在声明一个_strong 来修饰weakSelf 就行了。
下面是afnetworking中的源码,既处理了循环引用的问题,又防范了突发情况的产生,处理方式值得借鉴:
__weak __typeof(self)weakSelf = self;
AFNetworkReachabilityStatusBlock callback = ^(AFNetworkReachabilityStatus status) {
__strong __typeof(weakSelf)strongSelf = weakSelf;
strongSelf.networkReachabilityStatus = status;
if (strongSelf.networkReachabilityStatusBlock) {
strongSelf.networkReachabilityStatusBlock(status);
}
};