美文网首页iOS面试相关iOSOC底层相关
weakSelf 和 strongSelf 应该什么时候用?

weakSelf 和 strongSelf 应该什么时候用?

作者: xbcoding | 来源:发表于2019-01-18 17:38 被阅读72次

    1、为什么会出现block的循环引用?

    block一般在对象内部声明(Block 会 retain ‘self’),若在block内部使用了当前对象的属性(‘self‘ 又 retain 了 Block),就会造成循环引用,从而引起内存泄露,block和当前对象都无法释放。
    @weakify / weakSelf :将当前对象声明为weak,这样block内部引用当前对象,就不会造成引用计数+1,可以破解循环引用。
    @strongify / strongSelf :相当于声明一个局部的strong对象,等于当前对象。可以保证block调用的时候,内部的对象不会释放。

        __weak typeof(self) weakSelf = self;
        block = ^(){
              __strong typeof(weakSelf) strongSelf = weakSelf;
            
              // strongSelf.property
        };
    

    typeof()和__typeof()和typeof()都是C的扩展,只是针对不同的 c语言编译版本 有所不同, 而在gun99和c99及以后的版本中三者通用。

    2、原文:iOS block中weakSelf和strongSelf的使用(分别什么时候用)

    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。

    相关文章

      网友评论

        本文标题:weakSelf 和 strongSelf 应该什么时候用?

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