1. 使用场景
一般我们在使用block的时候, 都会特意去注意一个问题--循环引用的问题, 根据OC的引用计数机制, 当对象的引用计数为0的时候, 系统会释放这个对象. 循环引用会导致我们的对象不能正常释放, 类似资源争夺的现象, 释放A的条件是B的释放, 而释放B的条件是释放A.
1.1 声明一个是TestViewController里面定义一个block--callBack
@interface TestViewController : UIViewController
@property (nonatomic, copy) void(^callBack)(NSString* name);
@end
1.2在viewDidLoad里面实现并调用block
- (void)viewDidLoad {
[super viewDidLoad];
[self setCallBack:^(NSString *name) {
NSLog(@"%@ %@", self, name);
}];
self.callBack(@"come on");
}
- (void)dealloc
{
NSLog(@"%@ dealloc ", self);
}
这个代码里面是一个最基础的循环引用问题(测试贴图), 一般我们解决此类问题需要有一个弱引用也就是我们所要讲述的__weak,代码如下
- (void)viewDidLoad {
[super viewDidLoad];
__weak typeof(self) weakSelf = self;
[self setCallBack:^(NSString *name) {
NSLog(@"%@ %@", weakSelf, name);
}];
self.callBack(@"come on");
}
这样的话, TestViewController就可以正常的dealloc了.
2. 注意事项
这样写会存在一定的隐患, 因为__weak类型在这里是个局部变量, 而且weak属性有个特点就是自动置为nil, 所以有可能在我们去使用weakSelf的时候, weakSelf已经是空值了.
- (void)viewDidLoad {
[super viewDidLoad];
__weak typeof(self) weakSelf = self;
[self setCallBack:^(NSString *name) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[NSThread sleepForTimeInterval:5];
NSLog(@"%@ %@", weakSelf, name);
});
}];
self.callBack(@"come on");
}
输出结果是
2017-12-23 11:50:00.450854+0800 循环引用问题[5620:207264] <TestViewController: 0x7fc43ae025b0> dealloc
2017-12-23 11:50:02.952027+0800 循环引用问题[5620:207367] (null) come on
会先delloc, 然后才会走block里面的代码. 可以看到此时的weakSelf已经是null了, 如果我们做如下修改
- (void)viewDidLoad {
[super viewDidLoad];
__weak typeof(self) weakSelf = self;
[self setCallBack:^(NSString *name) {
__strong typeof(weakSelf) strongSelf = weakSelf;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[NSThread sleepForTimeInterval:5];
NSLog(@"%@ %@", strongSelf, name);
});
}];
self.callBack(@"come on");
}
输出结果如下
2017-12-23 11:57:05.182026+0800 循环引用问题[5709:215351] <TestViewController: 0x7ff217725e50> come on
2017-12-23 11:57:05.182414+0800 循环引用问题[5709:214769] <TestViewController: 0x7ff217725e50> dealloc
__strong可以使block对self进行强制持有, 使他的retainCount+1, 使self不能dealloc, 而strongSelf是个局部变量, 当block结束的时候就会自动释放掉, 所以此时的self的self的retainCount-1, 然后可以释放掉self.
- (void)viewDidLoad {
[super viewDidLoad];
__weak typeof(self) weakSelf = self;
[self setCallBack:^(NSString *name) {
NSLog(@"strong之前:%lu", CFGetRetainCount((__bridge CFTypeRef)(((NSObject *)weakSelf))));
__strong typeof(weakSelf) strongSelf = weakSelf;
NSLog(@"strong之后:%lu", CFGetRetainCount((__bridge CFTypeRef)(((NSObject *)weakSelf))));
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[NSThread sleepForTimeInterval:5];
NSLog(@"%@ %@", strongSelf, name);
});
}];
self.callBack(@"come on");
}
输出结果是
2017-12-23 12:01:57.725400+0800 循环引用问题[5782:221024] strong之前:10
2017-12-23 12:01:57.725636+0800 循环引用问题[5782:221024] strong之后:11
2017-12-23 12:02:02.729803+0800 循环引用问题[5782:221561] <TestViewController: 0x7f8bc6f04230> come on
2017-12-23 12:02:02.730176+0800 循环引用问题[5782:221024] <TestViewController: 0x7f8bc6f04230> dealloc
可以看到strong之后的retainCount+1了.
网友评论