weak:修饰属性,对属性赋值的时候不会对对象retain,引用计数也不会+1,并且当所引用的对象为nil时,该属性也就变为nil
strong:与weak 不同,strong修饰属性,对属性赋值时,会对对象retain,并且应用计数会+1.
在项目开发中,要值得注意的就是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];
打印的结果是:
block之前 rataincount:5
block之后 rataincount:7
发现并不是+1,而是+2了。这是由于block在创建的时候在堆上,而赋值给全局变量的时候,拷贝到栈上了。由于block对这个对象的强引用,就导致了,只要block不释放,那么所引用的对象也就没办法释放-1.导致对象的delloc方法无法执行。
然后我们在执行一段代码发现
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中调用函数时,又是什么情况
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
再来看网上的一个例子:
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++) {
// 模拟一个耗时的任务
}
NSLog(@"耗时的任务 结束 TestObj对象地址:%@",weakObj);
});
};
NSLog(@"after block retainCount:%zd",[obj arcDebugRetainCount]);
block();
输出结果:
before block retainCount:1
after block retainCount:1
TestObj对象地址:<TestObj: 0x602000006af0>
TestObj 对象已释放
耗时的任务 结束 TestObj对象地址:(null)
在这个线程之前是没有被释放的,但是当执行完耗时任务的时候,对象是被释放了。
而要解决这个问题 需要 __strong TestObj *strongObj = weakObj;这样耗时任务之后就不会被释放
__weak 修饰的对象被block引用,不会影响释放。而__strong在Block内部修饰的对象,会保证在使用这个对象在scope内,这个对象都不会被释放,出了scope,引用计数就会-1,且__strong主要是用在多线程运用中,若果只使用单线程,只需要使用__weak就行。
那么block中嵌套,又应该怎么修饰呢
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;
};
};
这样就可以避免循环引用