从XCode 4.2开始,提供了对ARC的支持。ARC不同于普通的垃圾回收机制,相比之下,更像一个在编译时候对代码进行分析的工具。ARC支持iOS4和iOS5. 同时XCode提供了用来进行ARC转换的新工具,可以一次性全部转换,也可以单独转换某些文件而保留其他文件使用手工计数。
ARC推出的目的是为了让开发者不需要去留心复杂的引用关系,有更多的精力去设计更好的画面,以及更优良的框架结构。
ARC会在代码编译的时候,加入一些代码,来确保对象在正确的时候被释放。概念上来说,ARC采用了引用计数的机制,替你完成那些retain,relese和autorelease方法的调用。
为了确保自动代码生成的正确性,ARC约束了可以使用的方法,以及使用toll-free bridging 的条件。(toll-free bridging是指Objc中可以相互替换使用的数据类型,例如NSLocal 和 CFLocal),同时,ARC也引进了一些新的生命周期定义符 Strong(retian),Weak(assgin)。同时引入 0 弱引用。弱引用不会增加它指向对象的生命周期,0弱引用是指当它指向的对象被释放时,这个弱引用会自动变为nil(assgin在这种情况下会变成一个野指针)。同时,ARC不会去检测互相引用(Retain Cycle)所以要特别小心。
以上是参数属性,还有一些变量声明周期相关的: __strong,__weak,__unsafe_unretained,__autoreleasing.(iOS4不支持__weak)
__strong 是默认的,__weak是0弱引用,__unsafe_unretained是非0弱引用,当指向的对象被释放时,会变成野指针。 __autoreleasing 使用来传输那些autorelease类型的引用参数的。
在栈上使用__weak时候,要特别小心。因为栈释放速度比较快。传递引用参数的时候也需要注意类型,因为默认的是__strong,而参数引用默认的修饰符是__autoreleasing.所以需要显示声明。
ARC中还提供了一种新的方法来使用AutoReleasePool: @autoreleasepool { //Code },这种方法比原来的对象更高效。
ARC中,栈上新建的变量(非)初始值都是nil。对于IB的Outlet来说,除了FileOwner的或者最顶级的元素为strong之外,其他的都应该是weak类型。
toll-free bridging: 在Core Foundation中,CF打头的对象的内存是不会被自动管理的,需要手工的调用CFRetain或者CGRelease。如果对CF对象和Objc对象进行转换,需要显示的告诉编译器这些对象引用类型的语义:
NS_INLINE CFTypeRef CFBridgingRetain(id X) {
return (__bridge_retain CFTypeRef)X;
}
NS_INLINE id CFBridgingRelease(CFTypeRef X) {
return (__bridge_transfer id)X;
}
或者
id my_id;
CFStringRef my_cfref;
...
NSString *a = (__bridge NSString*)my_cfref; // Noop cast.
CFStringRef b = (__bridge CFStringRef)my_id; // Noop cast.
...
NSString *c = (__bridge_transfer NSString*)my_cfref; // -1 on the CFRef
CFStringRef d = (__bridge_retained CFStringRef)my_id; // returned CFRef is +1
最后,还有一些ARC中间注意的事项:1 不能调用或者继承retain,release和autorelease
2 不能调用dealloc
3 不能使用autoreleasepool对象
4 init方法必须付值,[super init]是不对的,self = [super init]才正确
5 不能自定义retain和release方法,如果必须要,继承这个方法:-(BOOL)supportsWeakPointers { return NO; }
6 C结构中不能使用strong的对象,如果要使用对象,使用__unsafe_retained类型。
7 id 和 void*不能互转。
还有一些Q&A:
1 Q: 还要继续写dealloc方法么?
A: 视情况而定,ARC只是加减计数器,不会负责释放,而且对于那些文件资源,还是需要dealloc方法来释放资源。但是再里面不需要再去释放成员对象了。也不需要调用 [super dealloc]。但是在系统class或者那些没有使用ARC的类,可能需要调用[systemClassInstance setDelaget:nil].