探讨OC的内存管理 以及防止循环引用retain cycle 代理为什么用weak block为什么用copy

首先声明OC的内存管理机制:引用计数。

当一个对象的引用计数为0时,这个对象就会被释放。

铭记以上两点,我们开始来探讨。

换句话说,如果一个对象,没有强指针指向,就会被释放。

举个很形象的例子,假如每一个对象都是一只狗,每一个强指针都是狗链子,狗链子的数量就是引用计数。那么情况就会变成这样:当一个狗没有被狗链子拴着的时候,它就跑了。哈哈~

那么什么情况下又会造成循环引用呢?顾名思义,就是两个对象相互强引用,就会导致retain cycle.根据OC的内存管理机制,只有引用计数为0的时候对象才会被释放。很显然循环引用的直接结果就是导致两个对象都释放不掉造成内存泄漏。
举一个非常简单的循环引用的例子:

NSMutableArray *arr1 = [NSMutableArray array];
NSMutableArray *arr2 = [NSMutableArray array];
[arr1 addObjectsFromArray:arr2];
[arr2 addObjectsFromArray:arr1];

很明显,arr1和arr2谁都不会被释放,因为它们相互持有。
也是因此,代理属性要声明为assign或者weak,那同理,block也要注意循环引用。
但是代理和block声明的时候是相反的,代理要用weak,block要用copy.

为什么代理用weak或assign?

我们在ViewController.h中声明一个委托,并写一个代理属性。
探讨OC的内存管理 以及防止循环引用retain cycle 代理为什么用weak block为什么用copy_第1张图片

然后在ViewController.m中调用代理
调用

在SecondViewController.m中遵守协议,并成为ViewController的代理,实现代理方法。
探讨OC的内存管理 以及防止循环引用retain cycle 代理为什么用weak block为什么用copy_第2张图片

上图少了一行代码:[self.view addSubview:viewVC.view]这里的重点是,viewVC.delegate = self; 这一行代码,这时,我们回看在ViewController中的代理属性@property(nonatomic, weak) id delegate. 相当于这个id类型现在就是SecondViewController类型,换句话说,就是ViewController对SecondViewController进行了引用,这里是weak,所以是弱引用。而SecondViewController对ViewController进行了强引用。
所以,如果delegate属性声明为strong,就会造成循环引用。

为什么Block属性用copy

内存分为五个区:栈区、堆区、常量区、代码区、静态区(全局区)。

Block用copy修饰可以拷贝到堆区,以便我们程序员管理。它本身默认是在栈区,由系统管理,什么时候释放不确定,为了避免访问野指针,所以应该把它放在堆区。

注意:在ARC下,声明出来的block属性,不管用strong还是copy,编译器都会对这个block进行copy操作。即便如此,还是推荐使用copy来修饰,这样也能提醒你,编译器会对block进行copy操作。

另一方面,block也会经常导致循环引用,所以通常的做法就是,在外部创建一个weakSelf(用__weak修饰的self),来防止循环引用。这里最好在block内部再声明一个strongSelf(用__strong来修饰weakSelf).这是因为保证代码在执行block期间,self不会被释放,当block执行完后,会自动释放该strongSelf;

你可能感兴趣的:(开发小心得,iOS开发实用小知识)