美文网首页iOSiOS新手学习iOS
iOS block中weakSelf和strongSelf的使用

iOS block中weakSelf和strongSelf的使用

作者: coderJerry01 | 来源:发表于2016-09-29 13:54 被阅读6035次

    One problem with using blocks and asynchronous dispatch is that you can get into a retain cycle – the block can retain ‘self’, sometimes in mysterious ways. For instance, if you reference an ivar directly, what appears in the code is ‘theIvar’, the compiler generates ‘self->theIvar’. Thus, ‘self’, as a strong variable, is retained, and the queue retains the block, and the object retains the queue.

    Apple recommends first assigning ‘self’ into a weak automatic variable, then referencing that in a block (see 1). Since the block captures the variable along with its decorators (i.e. weak qualifier), there is no strong reference to ‘self’, and the object can get dealloced, and at that moment the weak captured variable turns to nil.

    大致意思是:

    Block 也会引起一些循环引用问题(retain cycle)—— Block 会 retain ‘self’,而 ‘self‘ 又 retain 了 Block。因为在 ObjC 中,直接调用一个实例变量,会被编译器处理成 ‘self->theVar’,’self’ 是一个 strong 类型的变量,引用计数会加 1,于是,self retains queue, queue retains block,block retains self。

    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];

    });

    clang 的文档表示,在 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 不会被释放。

    总结

    1 在 Block 内如果需要访问 self 的方法、变量,建议使用 weakSelf。

    2 如果在 Block 内需要多次 访问 self,则需要使用 strongSelf。

    参考:

    https://dhoerl.wordpress.com/2013/04/23/i-finally-figured-out-weakself-and-strongself/

    http://stackoverflow.com/questions/21113963/is-the-weakself-strongself-dance-really-necessary-when-referencing-self-inside-a?rq=1

    相关文章

      网友评论

      • _小沫:不是所有block里都需要弱引用,确定GCD里要弱引用?
      • _____柠檬:原来如此 谢谢楼主分享
      • 卓敦:可以strong直接修饰self吗,不用通过weakself
      • 卓敦:楼主,那我更新UI界面时,在主线程的代码需要把self改成weakself吗,还有UIview的动画方法,也需要改成weakself吗
        coderJerry01:@卓敦 当然没必要了
        卓敦:@Jason_Developer 如果我只是在主线程刷新一下tableview,要加弱引用吗。
        coderJerry01:@卓敦 主线程的self 如果涉及到block操作,并且block中有多个self调用方法,最好还是弱引用;uiview的方法不用了。 其实我个人的习惯是只要block中有多种 像[self 函数方法];这种操作 我都会将self弱引用的。
      • ethan_cun: TextViewController * __weak weakSelf = self;
        dispatch_async(dispatch_get_global_queue(0, 0), ^{

        for (NSInteger i=0; i<10000; i++) {
        [weakSelf log:@""];
        }
        });

        多次调用weakSelf 子线程 耗时 仍然走dealloc 什么原因 strongSelf有必要吗 很困惑
        另外 我释放block也一样啊 还好封装一些 没必要写weakSelf strongSelf到处写宏
        ethan_cun:这个应该是会释放的吧 没道理不释放啊 楼主有没有其他原因导致释放不了 比如写在根控制器

        我好奇weakSelf如果在耗时中被释放 再调用log方法应该是会崩溃的 但是并没有出现nil调用log方法导致崩溃的问题

        另外这里子线程的block里引用了self 但是self好像并没有引用block啊 这里应该是没有循环引用
        coderJerry01:你好,并不知道你的代码什么情况。按照你给出的代码,我试着写了一下,我的代码并不走dealloc,并且这个循环 10000个简单的数据 耗时 2.604266,复杂一些的话 应该也可以接受的。“strongSelf使用过程中,是循环引用的,不然block执行到一半,self释放掉,就达不到“self在block执行过程中不被释放”的效果了。但是,strongSelf是局部变量,在block执行完毕之后,strongSelf会释放,self的retainCount-1,不会影响self的释放。

        这里关键是weakSelf。block在声明时,会将其需要用到的常量copy,object的retainCount+1,也就是保留需要用到的上下文。而weakSelf的作用就是,让block在声明期间不会给self的retainCount+1,而在执行期间才用strongSelf给self的retainCount+1。从而,block在不执行的时候,不会影响self的释放。” 这是@CodeCola 回复Singleton_1990的一个解答,我觉得@CodeCola对这个的理解比我更加的好,所以你可以咨询一下他哦。
        ethan_cun:更正一下,仍然走dealloc的同时没有出现崩溃
      • 程旭媛:dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        楼主,请问这行代码一般都是在哪里使用呢?
        coderJerry01:dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{};这是多线程操作的一种方式(GCD开启多线程);使用的地方多数在于耗时操作,异步获取数据等地方。具体的建议搜索一下它的使用方法。。。:relaxed:
      • Lol刀妹:“在 doSomething 中,weakSelf 不会变成 nil,不过在 doSomething 执行完成,调用第二个方法 doOtherThing 的时候,weakSelf 有可能被释放”。如果能给个具体例子就更好了😀
      • 534b11fb9431:感谢作者,终于初步明白为何要代码块前弱引用处理self了
        coderJerry01:@潇洒胖乎乎 感谢来访:blush: 只是记录一些自己的疑问以及项目中遇到的问题,万一别人也有相同的麻烦呢!共同进步。。。
      • CodeCola:楼主啊。“clang 的文档表示,在 doSomething 内,weakSelf 不会被释放” 这条是哪里看到的?为毛我看到的是这样子的:

        - (void)configureBlock {
        XYZBlockKeeper * __weak weakSelf = self;
        self.block = ^{
        [weakSelf doSomething]; // capture the weak reference
        // to avoid the reference cycle
        }
        }

        By capturing the weak pointer to self, the block won’t maintain a strong relationship back to the XYZBlockKeeper object. If that object is deallocated before the block is called, the weakSelf pointer will simply be set to nil.

        也就是说你在执行doSomething的时候,也有可能被释放。
        开心小锣鼓:使用strongSelf 不就循环引用了吗?
        CodeCola:@Jason_Developer @Jason_Developer 多谢多谢:+1: :+1: :+1: 跟楼主一样,我也有个习惯,就是只要碰到block,我都会用weakSelf来引用self,内部再strongSelf引用weakSelf。看了楼主的文章,才知道不完全必要啦:)

        还有self的释放时机一直有困惑,这次彻底理解了——strongSelf是在block内创建,是个局部变量,block执行完毕,就会release掉。那么同时会减去对self的一次retain计数,不会影响到self的dealloc。

        “clang 的文档表示,在 doSomething 内,weakSelf 不会被释放”这一条在您给的链接中看到了,我回头查下clang文档,再次感谢!

        楼主,上一条评论有一点瑕疵——“当然不是见到block就要弱引用,您列举的例子确实是不需要的。同样也是可以释放的。” 我给的那个例子是需要weak引用的,不然self持有block,block持有self,互相持有了。
        coderJerry01:感谢您的评论与疑问,可能是理解的问题, weakself和strongself结合GCD使用的时候会更加明显的说明这个问题,看到过这样的说法:
        One problem with using blocks and asynchronous dispatch is that you can get into a retain cycle – the block can retain ‘self’, sometimes in mysterious ways. For instance, if you reference an ivar directly, what appears in the code is ‘theIvar’, the compiler generates ‘self->theIvar’. Thus, ‘self’, as a strong variable, is retained, and the queue retains the block, and the object retains the queue.

        Apple recommends first assigning ‘self’ into a weak automatic variable, then referencing that in a block (see 1). Since the block captures the variable along with its decorators (i.e. weak qualifier), there is no strong reference to ‘self’, and the object can get dealloced, and at that moment the weak captured variable turns to nil.
        导致意思是:
        Block 也会引起一些循环引用问题(retain cycle)—— Block 会 retain ‘self’,而 ‘self‘ 又 retain 了 Block。因为在 ObjC 中,直接调用一个实例变量,会被编译器处理成 ‘self->theVar’,’self’ 是一个 strong 类型的变量,引用计数会加 1,于是,self retains queue, queue retains block,block retains self。
        也许是习惯,在使用gcd的时候 一般我会直接用宏定义将self弱引用化。当然不是见到block就要弱引用,您列举的例子确实是不需要的。同样也是可以释放的。

      本文标题:iOS block中weakSelf和strongSelf的使用

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