Blocks篇:7.循环引用问题
1.ARC下的Block循环引用
1.1 使用weak或unsafe_unretained避免循环引用
一般来说,最简单的这种情况即:block对象作为OC对象的成员,而在block函数体内部直接或间接捕获了该OC对象,造成互相强引用。举例来说:
产生循环引用的过程:
- 由于myBlock对象捕获了OC对象(self),myBlock被自动拷贝到堆上,并自动对self产生强引用;
- myBlock是self的成员,当myBlock分配到堆内存后,self负责对其进行内存管理,自动对myBlock对象产生强引用;
- 互相保留,引用循环产生
不过这种情况,编译器可以直接识别并给出引用循环警告。我们可以通过所有权修饰符weak或unsafe_unretained,使myBlock对象通过保留弱引用或不安全的对象指针,来避免对self产生强引用:
|
|
由于在init方法中不比担心self对象释放的问题,可以安心使用__unsafe_unretained修饰符。
1.2 通过__block变量,并适时将其释放来解除循环引用
|
|
由于在ARC下,复制到堆内存中的block对象会对内部的OC对象进行强引用,故可以让block对象捕获block对象,并在需要时释放__block对象(一般都是执行block时),以间接解除对self的强引用。
补充:
调用block后,直接将block对象释放也可以解除循环引用。
缺点:
一般来说,必须执行block后,引用循环才可以被解除,容易出现遗漏的情况。
2.非ARC下的Block内存控制
2.1 非ARC下的Block引用循环
由于非ARC环境下,无法使用所有权修饰符,故只能通过__block变量的方式来解决引用循环问题:
|
|
在上述代码中,直接使用__block对象即可,无需释放,即可避免生成引用循环。
原因:
非ARC环境下,__block变量被分配到堆内存时,不会对内部的OC对象进行强引用;
因此,在block对象函数内部,不会对OC对象发生强引用,相当于ARC下的weak和unsafe_unretained的情况。
2.2 非ARC环境下的Block内存使用规则补充
- 对不同内存区域的block执行retain和copy操作的结果:
block对象所在的内存区域 | 执行操作 | 效果 |
---|---|---|
栈 | retain | 无效 |
栈 | copy | 复制到堆内存 |
堆 | retain | 产生强引用 |
堆 | copy | 产生强引用 |
- 在C语言环境下,可以使用Block_copy()和Block_release()对堆内存的block对象进行内存管理。