1. 使用場(chǎng)景
??一般我們?cè)谑褂胋lock的時(shí)候, 都會(huì)特意去注意一個(gè)問(wèn)題--循環(huán)引用的問(wèn)題, 根據(jù)OC的引用計(jì)數(shù)機(jī)制, 當(dāng)對(duì)象的引用計(jì)數(shù)為0的時(shí)候, 系統(tǒng)會(huì)釋放這個(gè)對(duì)象. 循環(huán)引用會(huì)導(dǎo)致我們的對(duì)象不能正常釋放, 類(lèi)似資源爭(zhēng)奪的現(xiàn)象, 釋放A的條件是B的釋放, 而釋放B的條件是釋放A.
1.1 聲明一個(gè)是TestViewController里面定義一個(gè)block--callBack
@interface TestViewController : UIViewController
@property (nonatomic, copy) void(^callBack)(NSString* name);
@end
1.2在viewDidLoad里面實(shí)現(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);
}
這個(gè)代碼里面是一個(gè)最基礎(chǔ)的循環(huán)引用問(wèn)題(測(cè)試貼圖), 一般我們解決此類(lèi)問(wèn)題需要有一個(gè)弱引用也就是我們所要講述的__weak,代碼如下
- (void)viewDidLoad {
[super viewDidLoad];
__weak typeof(self) weakSelf = self;
[self setCallBack:^(NSString *name) {
NSLog(@"%@ %@", weakSelf, name);
}];
self.callBack(@"come on");
}
這樣的話, TestViewController就可以正常的dealloc了.
2. 注意事項(xiàng)
這樣寫(xiě)會(huì)存在一定的隱患, 因?yàn)開(kāi)_weak類(lèi)型在這里是個(gè)局部變量, 而且weak屬性有個(gè)特點(diǎn)就是自動(dòng)置為nil, 所以有可能在我們?nèi)ナ褂脀eakSelf的時(shí)候, 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)引用問(wèn)題[5620:207264] <TestViewController: 0x7fc43ae025b0> dealloc
2017-12-23 11:50:02.952027+0800 循環(huán)引用問(wèn)題[5620:207367] (null) come on
會(huì)先delloc, 然后才會(huì)走block里面的代碼. 可以看到此時(shí)的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)引用問(wèn)題[5709:215351] <TestViewController: 0x7ff217725e50> come on
2017-12-23 11:57:05.182414+0800 循環(huán)引用問(wèn)題[5709:214769] <TestViewController: 0x7ff217725e50> dealloc
__strong可以使block對(duì)self進(jìn)行強(qiáng)制持有, 使他的retainCount+1, 使self不能dealloc, 而strongSelf是個(gè)局部變量, 當(dāng)block結(jié)束的時(shí)候就會(huì)自動(dòng)釋放掉, 所以此時(shí)的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)引用問(wèn)題[5782:221024] strong之前:10
2017-12-23 12:01:57.725636+0800 循環(huán)引用問(wèn)題[5782:221024] strong之后:11
2017-12-23 12:02:02.729803+0800 循環(huán)引用問(wèn)題[5782:221561] <TestViewController: 0x7f8bc6f04230> come on
2017-12-23 12:02:02.730176+0800 循環(huán)引用問(wèn)題[5782:221024] <TestViewController: 0x7f8bc6f04230> dealloc
可以看到strong之后的retainCount+1了.