iOS __weak、__block使用

2017-12-11  本文已影响26人  LYPC_下里巴人

总之这一切其实就是为了防止循环引用,下面结合网络上各位大牛的分析精华分析分析

block对于其变量都会形成强引用(retain),对于self也会形成强引用(retain) ,而如果self本身对block也是强引用的话,就会形成 强引用 循环,无法释放——造成内存泄露
什么是循环引用:对象A持有对象B,对象B持有对象A,相互持有,最终导致两个对象都不能释放。

循环引用场景:
1、block在主函数体用到了self / self.变量 / [self 方法],意味着:block对self 进行持有操作;
2、self声明了属性变量block,block用copy来修饰,意味着:self对block进行持有操作,会造成循环引用;
例如下图,现在这样写Xcode直接就会有警告出来告诉你这里貌似retain cycle了啊!!


循环引用例子

假如我想在block里面改变局部变量的值或者使用局部变量,如下图这么写Xcode直接报错 而且给出了解决方法提示出来了 这点还挺机智的,那么我们使用__block修饰之后,再次在block里面使用,就不会出问题了,完美。


解决


使用局部变量.png
在使用block的地方:
__block typeof(self) bself = self;          // 适用MRC模式,
__block NSString *tempStr = @"abc";
__block int a = 0; //当修饰变量时,表示这个变量值能在block中被修改
__weak typeof(self) weakself = self;     // 适用ARC模式

关于——Block在MRC和ARC模式的区别
1)__block在MRC下有两个作用
允许在Block中访问和修改局部变量
禁止Block对所引用的对象进行隐式retain操作

2)__block在ARC下只有一个作用
允许在Block中访问和修改局部变量

什么时候在 block 中不需要使用 weakSelf???

dispatch_async(dispatch_get_main_queue(), ^{
[self doSomething];
});

[UIView animateWithDuration:0.2 animations:^{
self.alpha = 1;
}];

.- (void) testWithBlock:(void(^)())block {
block();
}

__weak typeof(self) weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf doSomething];
});

因为将block作为参数传给dispatch_async时,系统会将block拷贝到堆上,而且block会持有block中用到的对象,因为dispatch_async并不知道block中对象会在什么时候被释放,为了确保系统调度执行block中的任务时其对象没有被意外释放掉,dispatch_async必须自己retain一次对象(即self),任务完成后再release对象(即self)。但这里使用__weak,使dispatch_async没有增加self的引用计数,这使得在系统在调度执行block之前,self可能已被销毁,但系统并不知道这个情况,导致block执行时访问已经被释放的self,而达不到预期的结果。

总结
1 在 Block 内如果需要访问 self 的方法、变量,建议使用 weakSelf。
2 如果在 Block 内需要多次 访问 self,则需要使用 strongSelf。

上一篇 下一篇

猜你喜欢

热点阅读