1. 使用場景
??一般我們在使用block的時候, 都會特意去注意一個問題--循環(huán)引用的問題, 根據(jù)OC的引用計數(shù)機制, 當對象的引用計數(shù)為0的時候, 系統(tǒng)會釋放這個對象. 循環(huán)引用會導致我們的對象不能正常釋放, 類似資源爭奪的現(xiàn)象, 釋放A的條件是B的釋放, 而釋放B的條件是釋放A.
1.1 聲明一個是TestViewController里面定義一個block--callBack
@interface TestViewController : UIViewController
@property (nonatomic, copy) void(^callBack)(NSString* name);
@end
1.2在viewDidLoad里面實現(xiàn)并調(diào)用block
- (void)viewDidLoad {
[super viewDidLoad];
[self setCallBack:^(NSString *name) {
NSLog(@"%@ %@", self, name);
}];
self.callBack(@"come on");
}
- (void)dealloc
{
NSLog(@"%@ dealloc ", self);
}
這個代碼里面是一個最基礎的循環(huán)引用問題(測試貼圖), 一般我們解決此類問題需要有一個弱引用也就是我們所要講述的__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, 所以有可能在我們?nèi)ナ褂脀eakSelf的時候, weakSelf已經(jīng)是空值了.
- (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");
}
輸出結(jié)果是
2017-12-23 11:50:00.450854+0800 循環(huán)引用問題[5620:207264] <TestViewController: 0x7fc43ae025b0> dealloc
2017-12-23 11:50:02.952027+0800 循環(huán)引用問題[5620:207367] (null) come on
會先delloc, 然后才會走block里面的代碼. 可以看到此時的weakSelf已經(jīng)是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");
}
輸出結(jié)果如下
2017-12-23 11:57:05.182026+0800 循環(huán)引用問題[5709:215351] <TestViewController: 0x7ff217725e50> come on
2017-12-23 11:57:05.182414+0800 循環(huán)引用問題[5709:214769] <TestViewController: 0x7ff217725e50> dealloc
__strong可以使block對self進行強制持有, 使他的retainCount+1, 使self不能dealloc, 而strongSelf是個局部變量, 當block結(jié)束的時候就會自動釋放掉, 所以此時的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");
}
輸出結(jié)果是
2017-12-23 12:01:57.725400+0800 循環(huán)引用問題[5782:221024] strong之前:10
2017-12-23 12:01:57.725636+0800 循環(huán)引用問題[5782:221024] strong之后:11
2017-12-23 12:02:02.729803+0800 循環(huán)引用問題[5782:221561] <TestViewController: 0x7f8bc6f04230> come on
2017-12-23 12:02:02.730176+0800 循環(huán)引用問題[5782:221024] <TestViewController: 0x7f8bc6f04230> dealloc
可以看到strong之后的retainCount+1了.