ios内存管理分为ARC和非ARC两个模式,具体开关在build setting - garbage。
同时,也可以混用两个模式,对特定的文件采用ARC或者非ARC:
Build Phases - Complie Sources 选中文件,
ARC 输入:-fobjc-arc
非ARC 输入:-fno-objc-arc
ARC的回收机制,也是建立在非ARC的基础上的,只是Xcode帮我们写了内存释放代码。而且用了ARC,同样会遇到引用计数异常的情况,特别是在block中。所以掌握非ARC的内存回收机制是必不可少的。
引用计数器
objectC的内存管理是建立引用计数器上:每一个内部对象都有一个整数(retainCount),这个整数就是“引用计数器”。alloc、retain、new、copy函数都会对这个对象的引用计数产生变化(+1),release是-1,小于等于0的时候就认为没有对象使用,可以回收(调用dealloc)。 这个就是一个基本的回收过程。
了解引用计数的概念后,相关的关键词还有:@property、自动释放池(@autoreleasepool)、自动引用计数(ARC)、循环引用。
@property
有三个参数类型。
原子 :atomic、nonatomtic。(和多线程有关)
读写 :readwrite、readonly。(生成getter、setter的区别)
set方法:assign、retain、copy。(对引用计数产生影响)
自动释放池。
在@autoreleasepool{ 代码块 } ,这个代码块里面的对象,只要调用autorelease方法,会在这个代码块的结束统一调用一次release。
ARC
- retain, release, autorelease, dealloc由编译器自动插入,不能在代码中调用
- dealloc虽然可以被重载,但是不能调用[super dealloc]
循环引用
案例一:对象A 有一个属性propertyA,对象B有一个属性delegateB。
如果是A.propertyA = B ; B.delegate = A。那么就会出现循环引用的问题。A 与 B相互引用,导致两边的引用计数都不为0,都无法回收内存。
解决方案:将B的delegate属性设置为weak。
案例二:对象A内,有一个代码块(block),在其中调用了self。
其实这个也是案例一的一种表示方式,只是对象B变成了一个A内部的代码块。
解决方案同上:将block里面的self声明为weak。(还不明白,可以看下Weak-Strong Dance)