美文网首页
weakSelf/strongSelf

weakSelf/strongSelf

作者: 二斤寂寞 | 来源:发表于2018-04-18 14:47 被阅读19次

    1.Retain Circle的由来

    当A对象里面强引用了B对象,B对象又强引用了A对象,这样两者的retainCount值一直都无法为0,于是内存始终无法释放,导致内存泄露。所谓的内存泄露就是本应该释放的对象,在其生命周期结束之后依旧存在。


    image.png

    这是2个对象之间的,相应的,这种循环还能存在于3,4……个对象之间,只要相互形成环,就会导致Retain Cicle的问题。

    当然也存在自身引用自身的,当一个对象内部的一个obj,强引用的自身,也会导致循环引用的问题出现。常见的就是block里面引用的问题。

    image.png

    2.weak、strong的实现原理

    在ARC环境下,id类型和对象类型和C语言其他类型不同,类型前必须加上所有权的修饰符。

    所有权修饰符总共有4种:

    1.strong修饰符 2.weak修饰符 3.unsafe_unretained修饰符 4.autoreleasing修饰符

    一般我们如果不写,默认的修饰符是__strong。

    要想弄清楚strong,weak的实现原理,我们就需要研究研究clang(LLVM编译器)和objc4 Objective-C runtime库了。

    关于clang有一份关于ARC详细的文档,有兴趣的可以仔细研究一下文档里面的说明和例子,很有帮助。

    3.weakSelf、strongSelf的用途

    Objective C 的 Block 是一个很实用的语法,特别是与GCD结合使用,可以很方便地实现并发、异步任务。但是,如果使用不当,Block 也会引起一些循环引用问题(retain cycle)—— Block 会 retain ‘self’,而 ‘self‘ 又 retain 了 Block。因为在 ObjC 中,直接调用一个实例变量,会被编译器处理成 ‘self->theVar’,’self’ 是一个 strong 类型的变量,引用计数会加 1,于是,self retains queue, queue retains block,block retains self。

    解决 retain circle
    Apple 官方的建议是,传进 Block 之前,把 ‘self’ 转换成 weak automatic 的变量,这样在 Block 中就不会出现对 self 的强引用。如果在 Block 执行完成之前,self 被释放了,weakSelf 也会变为 nil。

    示例代码:

    __weak __typeof__(self) weakSelf = self;
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        [weakSelf doSomething];
    });
    

    在 doSomething 内,weakSelf 不会被释放。但,下面的情况除外:

    __weak __typeof__(self) weakSelf = self;
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        [weakSelf doSomething];
        [weakSelf doOtherThing];
    });
    

    在 doSomething 中,weakSelf 不会变成 nil,不过在 doSomething 执行完成,调用第二个方法 doOtherThing 的时候,weakSelf 有可能被释放,于是,strongSelf 就派上用场了:

    __weak __typeof__(self) weakSelf = self;
       dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        __strong __typeof(self) strongSelf = weakSelf;
        [strongSelf doSomething];
        [strongSelf doOtherThing];
    });
    

    __strong 确保在 Block 内,strongSelf 不会被释放。

    要点总结:

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

    前面的写法虽然严谨了,也解决了问题了,但是作为喜欢偷懒的程序猿,会不会觉得很啰嗦?每次都要写那两条长长的__weak和__strong,而且在block里用到的self的全部要改成strongSelf,假设把一段很多self的代码拷贝到block里,一个个改成strongSelf是不是很蛋疼?

    4.@weakify、@strongify实现原理

    @weakify、@strongify,这两个关键字是RAC中避免Block循环引用而开发的2个宏,这2个宏的实现过程很牛。

    @weakify、@strongify的作用和weakSelf、strongSelf对应的一样。
    实现原理有兴趣的可以查看参考文章内写的。

    RAC的宏装逼过程总结

    其实总结起来很简单,就2点:

    • 通过metamacro_argcount确定可变参数个数x
    • 根据1得到的x调用metamacro_foreach_cxtx,层层递归,对每个参数进行宏替换

    参考文章:
    http://ios.jobbole.com/88708/
    http://www.cocoachina.com/ios/20161025/17303.html

    相关文章

      网友评论

          本文标题:weakSelf/strongSelf

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