美文网首页selector
Block经典问题循环引用&解决

Block经典问题循环引用&解决

作者: 6ffd6634d577 | 来源:发表于2019-08-01 17:48 被阅读0次

    Block内存关系
    Block经典问题循环引用&解决
    Block底层分析
    Block底层HooK

    1.循环引用怎么产生的?

    因为block的特性,声明block的对象都会以copy的形式持有block,而block对于它内部的对象也会进行强引用,从而导致了循环引用。

    简单来说就是在堆上的对象与堆上的对象互相引用造成的环,就会引起循环引用。

    2.OC中block在内存中是存放在什么位置?

    1. NSConcreteGlobalBlock
      全局block,存储在数据区,不会引起循环引用的问题。(因为没有捕获外部变量)
    2. NSConcreteStackBlock
      存储在栈上的block,内存管理由系统处理,不会引起循环引用问题
    3. NSConcreteMallocBlock
      这种block在堆上,如果捕获了外部对象,则会引起循环引用的问题。

    3.关键字__block 、__weak、__strong的作用

    __block 修饰的变量可以在block中被修改,具体实现细节很多大神都有讲解,各位同学可以先去看看内部原理,这里主要讲__weak、__strong在使用中的细节

    注意:在ARC下,只要将block赋值给一个变量,那么这个block就将被拷贝到堆上,这是编译器的优化。所以,这种情况下,block被强引用,block又对捕获的对象强引用,我们就必须使用__weak来打破循环

    __weak大家都很熟悉,对对象弱引用,以打破引用循环,解决问题。Weak原理请看这里

    但是使用__weak有一个问题,可能导致在block执行的过程中对象被释放了,这就是一个很严重的问题,如果在block之前被释放,还可以接受。

    下面看一个例子:这里可以看到,在执行block的时候,p被意外的释放了。

    @interface Persion : NSObject
    @property (nonatomic, copy)void(^block)();
    @end
    
    @implementation Persion
    - (void)dealloc {
        NSLog(@"%s",__func__);}
    
    - (instancetype)init {
        self = [super init];
        if (self) {
            __weak typeof(self) weakSelf = self;
            self.block = ^{
                dispatch_async(dispatch_get_global_queue(0, 0), ^{
                    [NSThread sleepForTimeInterval:1];
                    NSLog(@"%@",weakSelf);
                });
            };
        }
        return self;
    }
    
    @end
    
    -(void)test{
    Persion *obj = [Persion new];
     obj.block();
    }
    

    结果是打印的是(null),因为block里打印的方法是异步执行的,在 NSLog(@"%@",weakSelf);这句代码执行之前test函数就结束,所以obj对象已经被release了。

    怎么解决呢?所以再对weakSelf做一次 __strong就可以了:

    __weak typeof(self) weakSelf = self;
            self.block = ^{
                __strong typeof(weakSelf) strongSelf = weakSelf;
                dispatch_async(dispatch_get_global_queue(0, 0), ^{
                    [NSThread sleepForTimeInterval:1];
                    NSLog(@"%@",strongSelf);
                });
            };}
    

    使用了__strong在strongSelf变量作用域结束之前,对weakSelf有一个引用,防止对象(self)提前被释放。而作用域一过,strongSelf不存在了,对象(self)也会被释放。

    4.循环引用解决方法

    1.__weak弱引用
    2.@weakify , @strongify 这两个宏定义,参考这里

    相关文章

      网友评论

        本文标题:Block经典问题循环引用&解决

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