深刻理解block的循环引用

最近再次提到block循环引用的问题,因此在此做一个梳理。大致罗列下接下来的思路:

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

要想解决循环引用的问题,先要了解循环引用如何产生的。

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

听上去很拗口,不过这个概念很重要。

2.oc中block在内存中是存放在什么位置?堆?栈?

接下来再看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有一个问题,可能导致在block执行的过程中对象被释放了,这就是一个很严重的问题,如果在block之前被释放,还可以接受。下面看一个例子:

这里可以看到,在执行block的时候,p被意外的释放了。

被提前意外释放

如上图:在block执行期间,Person对象p被释放了,导致同一个block中代码前后执行的结果不一样。所以我们必须再在block中使用__strong来对p进行一次抢占,这样做的好处在于,在执行到block的时候,能够保证在block执行期间,对象都一直存在。如图:

__strong保证了在block执行周期对象都一直存在

如上图:使用了__strong保证了block执行时,如果对象没有被释放,那么整个块中都不会被释放


总结:为了避免循环引用,同时为了防止异步的block在回调的时,block执行的过程中被意外释放,我们使用__strong 对block外的__weak对象再次强引用,既能够防止引用循环,又能够保证代码的正确执行。

你可能感兴趣的:(深刻理解block的循环引用)