内存的循环引用
在 ARC,开发者将会定义一个变量为“strong”或“weak”。一个 weak 弱引用无法 retain 对象,而 strong 引用会 retain 这个对象,并将其引用计数加一。
循环引用就是指两个对象互相retain对方,通过OBJC的release是无法销毁这两个对象的
更严重的是,如果几个对象间接相互引用,比如a<-b b<-c c<-a 那么a、b、c都无法通过release释放
循环引用的场景
一、定时器NSTimer
二、block的使用
三、代理delegate
四、父子对象关系(swift)
定时器:
我们在使用NSTimer时经常会作为一个类的属性使用
而NSTimer在初始化的时候回指定self为target.这就造成了self—>NSTimer-->self的循环引用的情况。另外在NSTimer一致处于validata状态时其引用计数器一直是大于0的
解决办法:在不使用定时器以后要调用invalidata移除定时器。
block的使用
block在引用外部的变量是,会对外部变量进行copy操作。在(ARC)模式下会对变量进行强引用,(MRC)模式下变量retainCount加1。当一个类把block作为成员变量时,在block内部使用了这个类本身。造成self—>block-->self或者self-->block-->类的成员变量循环引用的情况。
解决办法:在MRC模式下,在给block赋值时在外部用__blockmySelf = self;用__block修饰使用到的类。
在ARC模式下,用__weak修饰
代理:
代理协议也是一个典型的场景,需要你使用弱引用来避免循环引用。将代理声明为 weak 是一个即好又安全的做法
父子对象关系
父子对象关系是一个循环引用的典型案例,不幸的是,它也是唯一一个存在于苹果文档中的案例。典型的解决方法就是,在子类定义一个指向父类的变量,声明为 weak 弱引用,从而避免循环引用。
在 swift 中子类指向父对象的变量是一个弱引用,这就迫使我们将该弱引用定义为 optional 类型。如果不使用 optional 可以有另一种做法,将指向父对象的变量声明为“无主引用(unowned)”(表明我们不持有该对象,也不对其进行内存管理)。然而在这种情况下,我们必须非常小心,确保只要还有子对象指向它,父对象不变成 nil,否则会直接闪退。
调试:
使用 Instruments 调试循环引用
XCode 自带了一个很强大的工具 Instruments,用于检测和定位循环引用。一旦你的 app 开发结束,即将提交到 Apple Store,先分析你的 app 是一个好的习惯。Instruments 有很多组件,可以用来分析 app 的不同方面,但是我们现在关心的是 Leak 选项。