美文网首页
iOS __weak、__block使用

iOS __weak、__block使用

作者: LYPC_下里巴人 | 来源:发表于2017-12-11 23:22 被阅读26次

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

    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???

    • 大部分GCD方法,因为self并没有对GCD的block进行持有,没有形成循环引用。目前我还没碰到使用GCD导致循环引用的场景,如果某种场景self对GCD的block进行了持有,则才有可能造成循环引用。

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

    • 大部分动画效果,当动画结束时,UIView 会结束持有这个 block,block 对象就会释放掉,从而 block 会释放掉对于 self 的持有。整个内存引用关系被解除。

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

    • block并不是对象的属性 / 变量,而是方法的参数 / 临时变量,这里因为block只是一个临时变量,self并没有对其持有,所以没有造成循环引用

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

    • 还有一种情况,block属于Person对象,在另一个类里面使用的时候没有构成互相持有,这时候也不需要weakSelf。

    • 使用GCD的时候,这么写其实是错误的,并不是见到block就要为了防止循环引用而使用weakSelf,像下面这种写法,就是错误的:

    __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。

    相关文章

      网友评论

          本文标题:iOS __weak、__block使用

          本文链接:https://www.haomeiwen.com/subject/fttwixtx.html