发生了什么事?
在ARC出现以前,程序员们只能靠retain/relese/autorelease来确保对象们恰好“坚持”到被需要的那一刻。如果忘了retain,或者多次release某个对象,程序就会发生内存泄漏的问题,甚至直接崩溃。
在Xcode 4.2中,除了语法检查外,Apple的新LLVM编译器还将内存管理的苦差事接了过来,它会检查代码,决定何时释放对象。Apple的文档里是这么定义ARC的:
“自动引用计数(ARC)是一个编译器级的功能,它能简化Cocoa应用中对象生命周期管理(内存管理)的流程。”
ARC使内存管理在大部分时候变得如同小事一桩,但我们仍要在决定自己的类如何管理其它对象的引用时承担一些责任。
那么,让我们正式开始吧……
手工管理、引用计数式的内存管理在iOS中是这样工作的: 当使用alloc/init(或其它类似方法)创建对象时,随同对象返回的,还有个retainCount,其值为1,表明我们获得了这个对象的所有权。
NSObject *obj = [[NSObject alloc] init]; // do some stuff [obj release];在对象的alloc/init和release(即放弃对象的所有权)之间,我们可以任意处理它,这很安全,因为系统是无法回收正在使用中的对象的。
将对象加入到自动释放池也是类似,对象会一直存在,直到未来的某个时间我们不再需要它,才会被系统回收。
-(NSObject*) someMethod { NSObject *obj = [[[NSObject alloc] init] autorelease]; return obj; // will be deallocated by autorelease pool later }
大多数新的iOS程序员都会在引用计数这问题上遇到理解障碍。ARC则是一个编译前的步骤,它为我们的代码自动加上retain/release/autorelease语句。
ARC并不是垃圾收集,而且,引用计数也没有消失,只是变成自动而已。听起来像是事后追加的这么一个功能,不过,只要我们想一想Objective-C有多少功能是通过对源文件的预处理来实现的,就不会这么想了。
当采用ARC后,代码只要这样写:
NSObject *obj = [[NSObject alloc] init]; // do some stuffARC会自动将它变成:
NSObject *obj = [[NSObject alloc] init]; // do some stuff [obj release]; // **Added by ARC**
从下图(来自Apple官方文档)看起来,好像retain/release的数量快赶上真正有用的代码了。当然,这肯定不是熟手的情况,不过可以看成是对新手的保守估计。这些代码跑起来,要跟踪某个内存问题真的是会搞死人。
4. C结构中的对象指针
同样禁止使用。文档里建议不要把它们放在结构了,改放到类里去。否则ARC就不认识它们了。可能会出现一些移植上的问题。不过,ARC是可以以文件为单位来关闭的。参考下文的“引入不兼容ARC的代码”。
5. id与void*之间的临时互转
当我们在Core Foundation的C函数和Foundation Kit的Objective-C方法间传递对象时,常常需要进行id和void*两个类型的互转。叫做免费桥接(Toll Free Bridging)。
如果使用ARC,必须在CF对象进入和脱离ARC的控制时,用提示/限定符来告知编译器。限定符有__bridge、__bridge_retain和__bridge_transfer。另外,仍需要用CFRetain和CFRelease来管理Core Foundation的对象。
这一块已经比较高深了,如果你不清楚CF对象是什么,也不需要太烦恼。
6. 以@autoreleasepool代替NSAutoReleasePool
兼容ARC的代码不能再使用NSAutoReleasePool对象,而要改用@autoreleasepool{}块。一个很好的例子:
int main(int argc, char *argv[]) { @autoreleasepool { return UIApplicationMain(argc, argv, nil, NSStringFromClass([ExampleAppDelegate class])); } }
7. 其它
基于Zone的内存已经没了(在运行时里也没了)。不能再使用NSAllocateObject和NSDeallocateObject。
身为程序员,习惯于做出一些决定,例如把某个量声明为变量还是常量、本地还是全局,等等。因此,在这里,我们也要决定某个属性与其它属性的关系。我们用strong/weak来把这一关系告诉编译器。
强引用
强引用是对某对象的引用,并且能阻止它被回收。换句话说,强引用创建了一个所有关系。在ARC之前,我们这么写:
// Non-ARC Compliant Declaration @property(retain) NSObject *obj;
在ARC下,我们需要这么写,以确保当前实例获得被引用对象的所有权(主人不被回收,它也不能被回收)。
// ARC Compliant Declaration @property(strong) NSObject *obj;
弱引用
弱引用是对某对象的引用,但不能阻止它被回收。换句话说,弱引用并不会创建所有关系。在ARC之前,我们这么写:
// Non-ARC Compliant Declaration @property(assign) NSObject *parentObj;在ARC下,我们需要这么写,以确保当前实例没有获得被引用对象的所有权(一般来说,子对象不应该拥有父对象,这时可以用弱引用)。
// ARC Compliant Declaration @property(weak) NSObject *parentObj;
上一节是说明如何管理属性。对于常规变量,则有:
__strong __weak __unsafe_unretained __autoreleasing一般来说,我们不太需要使用上面这些限定符。在使用移植工具的时候可能会看到那么几个,但新工程基本上不需要。
来源: http://clang.llvm.org/docs/AutomaticReferenceCounting.html#ownership
注: 我们发现在ARC下,@property中使用“retain”时(而不是“strong”),编译器并不会报错,而且能生成同样结果。但以后可能会变,所以还是用“strong”吧。
评论删除后,数据将无法恢复
评论(4)