很多刚入门的宝宝面对block是心虚的,因为一提到block就会联想到:如果用的不好会出现循环引用引起内存泄漏问题,有时候想用但是自己又没有能发现循环引用的洞察力,所以在遇到block存在的地方,就使用__weak type(self) weakSelf = self;(被视为解决循环引用的必备良药) 这句话加上确实能保证不会出现循环引用的情况,但是并不是所有使用block的地方都会出现循环引用的,所以这个要具体问题具体对待,该用时那必须得用,没必要的时候,也就没有必要画蛇添足了。
下面列举一处常见使用Block的例子,但是一般不会轻易出现循环引用,只要把关键点处理好就不会出现循环引用的问题。例子一:UIAlertController(弹出框视图控制器)想必大家再也熟悉不过了
//点击按钮弹出提示框
-(void)btnAction:(id)sender{
NSLog(@"弹出框");
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"弹出框" message:@"" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *ok = [UIAlertAction actionWithTitle:@"确定"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * _Nonnull action) {
NSLog(@"Class****%@",[self class]);
//明目张胆在block中引用self,很多惧怕block中引用self会出现循环引用的宝宝会来这么一句:
__weak type(self) weakSelf = self;
//接着NSLog(@"Class****%@",[weakSelf class]);然后心里才放心!其实这些都是画蛇添足,完全没有必要的!
}];
UIAlertAction *cancel = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil];
[alert addAction: ok];
[alert addAction:cancel];
[self presentViewController:alert animated:YES completion:nil];
}
这里把引用关系列一下就明白为什么安全无事了:
引用关系图.png
这里根本都没有造成闭环构成循环引用,前提是:你没有把UIAlertController对象或者UIAlertAction对象作为当前类的成员属性,一但self强引用了UIAlertController对象或者强引用了UIAlertAction对象,那么就构成闭环了,循环引用就会出现。一般编程中,没有必要把UIAlertController对象或者UIAlertAction对象作为当前视图控制器类的成员属性,去让self去持有它们的引用,一般都是像在本例中:在方法体中作为局部临时对象使用(self不会持有临时对象的引用),局部临时对象作用域只限制在方法体内部,也就是说这些临时对象的生命周期只限制在方法内部,一但方法执行完毕,这些临时创建的指针变量就会被置为nil
,如果指针被置为nil
,那么它原来所指临时对象就会被销毁。记住:局部指针变量,出了作用域就会被置为nil
,所指向的对象也会立即被系统释放。
想测试到底会不会出现循环引用的有一个很简单的方法:就是在self.navigationController中pop掉当前控制器对象的时候(前提使用UINavigationController作为根视图控制器),看看当前视图控制器类中dealloc方法是否被执行,如果成功执行说明没有其他对象引用当前即将要pop掉的视图控制器,如果不执行,那么基本可以断定是由于代码中出现了循环引用,导致内存泄漏,无法得到释放的缘故。