参考
Block循环引用的三种解决方式
iOS开发——Block引起循环引用的解决方案
iOS 控制器POP后dealloc方法不走,通知监听无法移除的问题
assign weak copy block __block与__weak的区别
Bug背景
自定义一个导航控件,在处理左右按钮点击事件时,没有采用代理方法,而是使用Block
#pragma mark - 重写父类-导航设置方法
- (void)setNavCoverView{
[super setNavCoverView];
self.navCoverView.style = NavCoverStyleWhite;
self.navCoverView.letfImgStr = @"login_icon_back";
self.navCoverView.midTitleStr = @"测试";
__block TestViewController *weakSelf = self;
self.navCoverView.leftBlock = ^{
[weakSelf.navigationController popViewControllerAnimated:YES];
};
}
- (void)dealloc{
NSLog(@"0-0-0-0-0");
}
以上代码中,由于使用了错误的 避免循环引用 方式 导致 dealloc() 方法不能被系统调用,这样是有问题的
经过测试 发现
self.navCoverView.leftBlock = ^{
//[weakSelf.navigationController popViewControllerAnimated:YES];
};
- (void)dealloc{
NSLog(@"0-0-0-0-0");
}
此时dealloc()方法被调用
问题出在 __block 上
__block:在ARC和MRC下都可用,可修饰对象,也可以修饰基本数据类型。
__block对象可以在block被重新赋值,__weak不可以。
__weak:只在ARC中使用,只能修饰对象,不能修饰基本数据类型(int、bool)。
同时,在ARC下,要避免block出现循环引用,经常会:__weak typedof(self) weakSelf = self;
__weak typeof(self) weakSelf = self;
self.navCoverView.leftBlock = ^{
[weakSelf.navigationController popViewControllerAnimated:YES];
};
使用 __weak 来避免循环引用 可避免导致 dealloc()方法不被调用
__weak typeof(self) weakSelf = self;
这句话的意思是声明了一个self类型的weak指针,名字叫做weakSelf. typeof是用来求参数类型的,这里也就是来求self的类型。这样定义出的weakSelf就是和self是一个类型,并且是原self的一个弱引用。
所以 也可以这样写
__weak MyViewController *weakSelf = self;
补充:
对于block的修饰 copy/weak (转http://blog.sina.com.cn/s/blog_134b6ff380102v1y1.html)
使用总结:
1.当block里面会有b类相关的参数要回调回去的时候,属性用copy修饰,将其拷贝到堆里面,这样即便栈释放掉了,b类的指针也在堆中存在,能够成功的回调回去。
2.如果语法块仅仅是执行而不再回调回去了, 比如操作某个数据库,修改某个单利类的属性,发送某个通知之类的,则可以用weak来修饰。有人会问:
为什么不能这里不都用copy呢,原因是 优化内存。 如果这个类要传入1000Block来执行,而这个类又不会马上释放掉的话,用copy是不是就拷贝了1000个在堆里面? 这样就会占用很大一部分内存,如果使用了weak将不必要的执行后就可以马上释放掉是不是就节约了很多的内存了。