探秘ios中block的循环引用问题
2017-02-28 本文已影响225人
blocky
hello,小伙伴们!
ios中自从引入了block,代理就在慢慢淡出我们的视野,那么block的使用大家都了解吗?它的循环引用机制大家都了解吗?接下来我们就来聊聊这个话题.
一,介绍下简单block的写法.
//a,typedef 定义下的block写法
typedef void(^cusBlock)();
@property (copy , nonatomic) cusBlock block;
//b,直接属性定义下的block写法
@property (copy , nonatomic) void (^customBlock)();
//还有很多写法,大家可以参考其它牛人的写法,这里就不做介绍了.
二,执行block代码块(customBlock)
self.customBlock = ^(){
self.name = @"lili";
NSLog(@"执行了block块的方法");
}
}
touchesBegan后
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
if (self.customBlock) {
self.customBlock();
}
}
输出结果:2017-02-27 19:30:46.815 text[15115:303861] 执行了block块的方法
三,block循环引用的结论
//先说结论,后面再来分析
如果 [block内部] 访问了 [外部强引用] 对象A ,那么 [block内部] 会自动产生一个 [强引用引用] 对象A;
如果 [block内部] 访问了 [外部弱引用] 对象A ,那么 [block内部] 会自动产生一个 [弱引用引用] 对象A;
四,分析循环引用,验证结论
a,上述代码强引用的示意图
block强引用示意图.png这样系统会抛出一个⚠️错误
强引用警告示意图.png执行完block代码后
block执行完成后强引用示意图.png这个提示告诉我们,block内部出现了循环引用(有强迫症的最好解决下,免得越积越多).
b,解决办法,大家都知道的弱引用就可以完美的解决问题了.示意图如下
block弱引用示意图.pngc,特殊情况
@interface BLPerson : NSObject
@property(copy, nonatomic) NSString *name;
@property (copy , nonatomic) void (^customBlock)();
@end
#import "BLPerson.h"
- (void)viewDidLoad{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
BLPerson *p = [[BLPerson alloc]init];
__weak typeof(p)weakp = p;
p.name = @"jack";
p.customBlock = ^(){
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
weakp.name = @"lili";
NSLog(@"%@==执行了block块的方法",weakp.name);
});
};
if (p.customBlock) {
p.customBlock();
}
}
运行结果:2017-02-28 11:17:23.519 text[4118:80908] (null)==执行了block块的方法
weakp.name =null,这是为什么了,在block里面我明明已经将 weakp.name = @"lili"赋值了啊.
经过分析这是因为,在执行dispatch_after这个block中代码的时候,由于weakp是弱引用,在这个时间差之间weakp已经被释放了,weakp为nil,意味着nil.name就没意义了.
解决办法:在customBlock里面用一个强引用在引用weakp就行了;
p.customBlock = ^(){
BLPerson *p1 = weakp;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
p1.name = @"lili";
NSLog(@"%@==执行了block块的方法",p1.name);
});
};
输出结果:2017-02-28 11:26:41.679 text[4280:84156] lili==执行了block块的方法;这个时候P1.name是有值的;
ps:在block里面定义的属性是不会造成强引用的;
本章总结:
请大家牢记这两个结论,理解透了没有block会阻碍你前进的步伐.
如果 [block内部] 访问了 [外部强引用] 对象A ,那么 [block内部] 会自动产生一个 [强引用引用] 对象A;
如果 [block内部] 访问了 [外部弱引用] 对象A ,那么 [block内部] 会自动产生一个 [弱引用引用] 对象A;
建议以后block里面如果没有特殊要求,建议都写成弱引用,避免造成自己都发现不了的bug.本文,如有误之处,请大家多多指教,我一定虚心学习,希望同大家共同进步.