ARC本质
ARC是编译器(时)特性,而不是运行时特性,更不是垃圾回收器(GC)。ARC相对于MRC,不是在编译时添加retain/release/autorelease这么简单。应该是编译期和运行期两部分共同帮助开发者管理内存。
在编译期,ARC用的是更底层的C接口实现的retain/release/autorelease,这样做性能更好,也是为什么不能在ARC环境下手动retain/release/autorelease,同时对同一上下文的同一对象的成对retain/release操作进行优化(即忽略掉不必要的操作);ARC也包含运行期组件,这个地方做的优化比较复杂,但也不能被忽略
ARC的开启与关闭
不同于XCode4可以在创建工程时选择关闭ARC,XCode5在创建的工程是默认开启ARC,没有可以关闭ARC的选项。
如果需要对特定文件开启或关闭ARC,可以在工程选项中选择Targets -> Compile Phases -> Compile Sources,在里面找到对应文件,添加flag:
- 打开ARC:-fobjc-arc
- 关闭ARC:-fno-objc-arc
ARC的修饰符
ARC下主要提供四种修饰符,分别是:
__strong
,__weak
,__autoreleasing
,__unsafe_unretained
。
__strong:
表示引用为强引用。对应在定义property时的"strong"。当对象被strong修饰,引用计数加1。所有对象只有当没有任何一个强引用指向时,才会被释放。
注意:如果在声明引用时不加修饰符,那么引用将默认是强引用。当需要释放强引用指向的对象时,需要将强引用置nil。weak:
表示引用为弱引用。对应在定义property时用的"weak"。弱引用不会影响对象的释放,即只要对象没有任何强引用指向,即使有100个弱引用对象指向也没用,该对象依然会被释放。不过好在,对象在被释放的同时,指向它的弱引用会自动被置nil,这个技术叫zeroing weak pointer。这样有效得防止无效指针、野指针的产生。__weak一般用在delegate关系中防止循环引用或者用来修饰指向由Interface Builder编辑与生成的UI控件。
原理:runtime 对注册的类, 会进行布局,对于 weak 对象会放入一个 hash 表中。 用 weak 指向的对象内存地址作为 key,当此对象的引用计数为0的时候会 dealloc,假如 weak 指向的对象内存地址是a,那么就会以a为键, 在这个 weak 表中搜索,找到所有以a为键的 weak 对象,从而设置为 nil。__autoreleasing:
没理解,可以参考http://www.cnblogs.com/flyFreeZn/p/4264220.html__unsafe_unretained:
ARC是在iOS 5引入的,而这个修饰符主要是为了在ARC刚发布时兼容iOS 4以及版本更低的设备,因为这些版本的设备没有weak pointer system,简单的理解这个系统就是我们上面讲weak时提到的,能够在weak引用指向对象被释放后,把引用值自动设为nil的系统。这个修饰符在定义property时对应的是"unsafe_unretained",实际可以将它理解为MRC时代的assign:纯粹只是将引用指向对象,没有任何额外的操作,在指向对象被释放时依然原原本本地指向原来被释放的对象(所在的内存区域)。所以非常不安全。copy:
如果属性指向的对象具有可修改的子类(NSArray,NSDictionary,NSString等),那么属性指针可能会指向这些子类。如果此时使用的是strong
,指向一个可变对象,如果这个对象又被其他对象持有,很可能会在不知情地修改值。使用copy
能在属性设置方法不保留新值,而是将其“拷贝” (copy),然后指向拷贝出来的新值,从而保持属性的封装性。
@property (nonatomic, copy) NSString *string_1;
@property (nonatomic, strong) NSMutableString *string_2;
self.string_2 = [[NSMutableString alloc] init];
self.string_1 = self.string_2;
//如果self.string_2被修改,self.string_1还是保持不变。
但是如果用copy
修饰可变属性的话,可能会引起崩溃
@property (nonatomic,copy) NSMutableArray *array;
添加,删除,修改数组内的元素的时候,程序会因为找不到对应的方法(unrecognised selector)而崩溃.因为 copy 就是复制一个不可变 NSArray的对象。
block 也经常使用 copy 关键字
block 使用 copy 是从 MRC 遗留下来的“传统”,在 MRC 中,方法内部的 block 是在栈区的,本身的作用域是属于创建时候的作用域,一旦在创建时候的作用域外面调用block将导致程序崩溃,使用 copy 可以把它放到堆区。在 ARC 中写不写都行:对于 block 使用 copy 还是 strong 效果是一样的,但写上 copy 也无伤大雅,还能时刻提醒我们:编译器自动对 block 进行了 copy 操作。
MRC的修饰符
assign:
1.assign和weak类似,但是assign指向的对象被销毁时候assign指针不会置为nil
2.assign 可以用非 OC 对象,而 weak 必须用于 OC 对象retain:
类似于ARC中的strong
-(void)setA:(ClassA *)a{
if(_a!=a){
[_a release];
_a=[a retain];
}
}