weak:修飾屬性,對屬性賦值的時候不會對對象retain,引用計數(shù)也不會+1,并且當(dāng)所引用的對象為nil時,該屬性也就變?yōu)閚il
strong:與weak 不同,strong修飾屬性,對屬性賦值時,會對對象retain,并且應(yīng)用計數(shù)會+1.
在項目開發(fā)中,要值得注意的就是block中,_weak和_strong的使用。下面我們來具體幾個實例方便理解
FirstViewController *firstVC=[FirstViewController new];
NSLog(@"block之前 rataincount:%zd",CFGetRetainCount((__bridge CFTypeRef)(self)));
firstVC.firstBlock = ^(NSString *str) {
};
NSLog(@"block之后 rataincount:%zd",CFGetRetainCount((__bridge CFTypeRef)(self)));
[self.navigationController pushViewController:firstVC animated:YES];
打印的結(jié)果是:
block之前 rataincount:5
block之后 rataincount:7
發(fā)現(xiàn)并不是+1,而是+2了。這是由于block在創(chuàng)建的時候在堆上,而賦值給全局變量的時候,拷貝到棧上了。由于block對這個對象的強引用,就導(dǎo)致了,只要block不釋放,那么所引用的對象也就沒辦法釋放-1.導(dǎo)致對象的delloc方法無法執(zhí)行。
然后我們在執(zhí)行一段代碼發(fā)現(xiàn)
FirstViewController *firstVC=[FirstViewController new];
NSLog(@"block之前 rataincount:%zd",CFGetRetainCount((__bridge CFTypeRef)(self)));
__weak typeof(self) wself = self;
firstVC.firstBlock = ^(NSString *str) {
};
NSLog(@"block之后 rataincount:%zd",CFGetRetainCount((__bridge CFTypeRef)(self)));
[self.navigationController pushViewController:firstVC animated:YES];
2021-03-02 14:56:59.214961+0800 RuntimeDemo[20368:7840960] block之前 rataincount:5
2021-03-02 14:56:59.215105+0800 RuntimeDemo[20368:7840960] block之后 rataincount:5
在block中調(diào)用函數(shù)時,又是什么情況
FirstViewController *firstVC=[FirstViewController new];
NSLog(@"block之前 rataincount:%zd",CFGetRetainCount((__bridge CFTypeRef)(self)));
__weak typeof(self) wself = self;
firstVC.firstBlock = ^(NSString *str) {
[wself textNameWith:str];
};
NSLog(@"block之后 rataincount:%zd",CFGetRetainCount((__bridge CFTypeRef)(self)));
[self presentViewController:firstVC animated:YES completion:^{
}];
2021-03-02 15:05:50.179184+0800 RuntimeDemo[20376:7844250] block之前 rataincount:5
2021-03-02 15:05:50.179469+0800 RuntimeDemo[20376:7844250] block之后 rataincount:5
再來看網(wǎng)上的一個例子:
TestObj *obj = [[TestObj alloc] init];
__weak TestObj *weakObj = obj;
NSLog(@"before block retainCount:%zd",[obj arcDebugRetainCount]);
block = ^(){
NSLog(@"TestObj對象地址:%@",weakObj);
dispatch_async(dispatch_queue_create(DISPATCH_QUEUE_PRIORITY_DEFAULT, NULL), ^{
for (int i = 0; i < 1000000; i++) {
// 模擬一個耗時的任務(wù)
}
NSLog(@"耗時的任務(wù) 結(jié)束 TestObj對象地址:%@",weakObj);
});
};
NSLog(@"after block retainCount:%zd",[obj arcDebugRetainCount]);
block();
輸出結(jié)果:
before block retainCount:1
after block retainCount:1
TestObj對象地址:<TestObj: 0x602000006af0>
TestObj 對象已釋放
耗時的任務(wù) 結(jié)束 TestObj對象地址:(null)
在這個線程之前是沒有被釋放的,但是當(dāng)執(zhí)行完耗時任務(wù)的時候,對象是被釋放了。
而要解決這個問題 需要 __strong TestObj *strongObj = weakObj;這樣耗時任務(wù)之后就不會被釋放
__weak 修飾的對象被block引用,不會影響釋放。而__strong在Block內(nèi)部修飾的對象,會保證在使用這個對象在scope內(nèi),這個對象都不會被釋放,出了scope,引用計數(shù)就會-1,且__strong主要是用在多線程運用中,若果只使用單線程,只需要使用__weak就行。
那么block中嵌套,又應(yīng)該怎么修飾呢
LHRModel *model = [LHRModel new];
__weak typeof(self) weakSelf = self;
model.dataChanged = ^(NSString *title) {
__strong typeof(self) strongSelf = weakSelf;
strongSelf.titleLabel.text = title;
__weak typeof(self) weakSelf2 = strongSelf;
strongSelf.model.dataChanged = ^(NSString *title2) {
__strong typeof(self) strongSelf2 = weakSelf2;
strongSelf2.titleLabel.text = title2;
};
};
這樣就可以避免循環(huán)引用