原文:http://longweekendmobile.com/2011/09/07/objc-automatic-reference-counting-in-xcode-explained/
名词解释:Automatic Reference Counting(ARC):自动引用计数
ARC在很大程度上消除了手动内存管理的负担,同时省去了追查内存泄露和过度释放对象引起的繁琐操作。尽管ARC非常吸引人,但是不会让你完全忽略内存管理。
下面的告示包含了ARC一些关键方面来帮助你快速建立和运行你的项目。
- Reference Counted Memory: Quick Revision
- How Automatic Reference Counting Works
- Enabling ARC in Your Project
- New Rules Enforced by ARC
- ARC Qualifiers – Declared Properties
- ARC Qualifiers – Regular Variables
- Migrating Existing Projects to ARC
- Including Code that is not ARC Compliant
- Should I Use ARC?
What Has Changed?
ARC之前,你必须手动的retain/release/autorelease对象来确保对应的对象存在,当你需要操作这些对象时。如果忘记retain一个对象,或者多次释放同一个对象,会导致应用内存泄露或者应用崩溃。
在Xcode4.3.2中,除了进行输入时语法检查,新的Apple LLVM编译器将手动管理内存的负担转移给编译器,内省你的代码决定何时进行对象释放。苹果文档描述ARC信息如下:“ARC is a compiler-level feature that simplifies the process of managing object lifetime(memory management) in Cacoa applications."
ARC减少了进行手动管理内存的琐碎的时间,但是你仍然需要拿出一些精力来处理如何管理你的类中对其他对象的引用。
让我们从头开始吧。。。
Reference Counted Memory:Quick Review
iOS中手动管理引用计数内存的工作方式如下:当使用alloc/init(or other similar method)创建一个对象,返回被创建对象的的retainCount为1,意味着你已经拥有了对象的所有权。
- NSObject *obj = [[NSObject alloc] init];
- // do somoe stuff
- [obj release];
在分配初始化一个对象与释放一个对象之间,你可以做你想做的操作,安全的对象不会被自动释放,当需要的时候可以被操作。
同样的,把一个对象添加到自动释放池中,当需要的时候,你操作的对象将继续有效 并且在将来的某个时刻不再被需要时,将被释放。
- - (NSObject *) someMethod
- {
- NSObject *obj = [[[NSObject alloc] init] aurorelease];
- return obj;// will be deallocated by autorelease pool later
- }
How Automatic Reference Counting Works
大部分iOS新手接触引用计数内存时都会陷入困境。ARC是在预编译阶段为你的代码添加retain/release/autorelease的。
这不是垃圾回收,引用计数内存没有消失,被用自动化的方式化繁为简。ARC听起来好像有点后续考虑的意味,但是细想一下,在Objectie-C中有多少功能在编译之前是通过预处理源文件的方式来实现的,ARC就是非常具有代表的课题。
当你使用ARC方式来编码时,代码格式如下:
- NSObject *obj = [[NSObject alloc] init];
- // do some stuff
- NSObject *obj = [[NSObject alloc] init];
- // do some stuff
- [obj release]; // ** Added by ARC **
下面的图表(来自苹果文档)好像暗指有效代码与retain/release的逻辑代码一样长。对于有Objective-C编码经验的人是不准确的,但是对于Objective-C的新人保守估计来看是这样的。
Enabling ARC in Your Project
New Rule Enfored by ARC
为了能通过ARC的方式进行编译,必须遵守一些规则。
1.alloc/init objects
像之前描述的,按照之前的方式创建对象,就不必再做retain/autorelease/retainCount操作。你不能间接的操作他们的selector:@selector(retain)和@selector(release)的操作将会被禁止。
2.dealloc methods
通常情况将会自动为你创建,你不必直接调用该方法。尽管你可以创建一个定制的dealloc方法来释放资源而不是实例变量。当创建是定制的方法时,不要调用[super dealloc]方法。编译器将会强行来为你做该操作。
3.declared properties
- // ARC Compliant Declaration
- @property(strong) NSObject *obj;
ARC之前,我们告诉编译器如何进行内存管理,使用assign/retain/copy参数的命令@property来声明公共属性。这些参数将不会在ARC中使用,我们会使用weak/strong参数来告诉编译器如何来操作属性。
4.object pointer in c structures
这是一个禁忌。文档建议使用类而不是结构体的方式来实现,这种方式非常有益因为结构体对于ARC是未知的。结构体将会引起额外的迁移麻烦。尽管,ARC基于文件是无效的。参见下面的"including code that is not ARC compliant"
5.casual(邂逅) casting between id and void*
当操作Core Foundation's C库与Foundation Kit's Objective-C库的方法时,在id与void*数据类型之间将会进行频繁的转换。就像我们所知道的 Toll Free Bridging(点击打开链接).
使用ARC你必须提供hints/qualifiers 来告诉编译器当CF对象进入或者退出控制范围来进行内存管理。这些标示符包括__bridge,__bridge_retain and __bridge_transfer.同时,你需要调用CFRetain和CFRelease 来进行内存管理 Core Foundation 对象。
这是一个非常高级的话题,如果你不知道CF Object,现在并不需要担心什么。
6.@autoreleasepool instead NSAutoReleasePool
ARC编译代码不能使用NSAutoReleasePool,必须使用@autoreleasepool{}块.任何一个ARC编译或迁移的工程中的main.m文件是一个非常好的例子。
- int main(int argc,char *argv[])
- {
- @autoreleasepool{
- return UIApplicationMain(argc,argv,nil,NSStringFromClass([ExampleAppDelegate class]));
- }
- }
基于内存的区域已经不存在啦(很明显说的不是在程序运行的时候);你不能使用NSAllocateObject 或NSDeallocateObject.
ARC Qualifiers - Declared Properties
作为编程人员,我们通常会决定是否定义一些局部或全局的变量或常量等等。同样,我们必须决定我们的和其他对象相关的属性。我们使用strong/weak标示符来告知编译器这些关系。
Strong References
一个对象的强引用会阻止被引用的对象被释放掉。换句话来讲,创建了一个所属关系。考虑到之前的情况,你将会这样来操作:
- // Non-ARC Compliant Declaration
- @property(retain) NSObject *obj;
- // ARC Compliant Declaration
- @property(strong) NSObject *obj;
Weak References
一个对象的弱引用不能阻止被释放掉。换句话来说,不能创建所有权拥有关系。
- // Non-ARC Compliant Declaration
- @property(assign) NSObject *parentObj;
- // ARC Compliant Declaration
- @property(weak) NSObject *parentObj;
ARC Qualifiers - Regular Variables
Variables Qualifiers
上面的例子描述了我们如何创建属性并进行管理,我们拥有的普通变量如下:
- __strong
- __weak
- __unsage_unretained
- __autoreleasing
__strong 是默认的类型,不需要打印。这意味着使用alloc/init创建的任何对象在当前有效范围内将保留整个生命周期。
__weak 指对象在任何时刻都能被销毁。__weak变量被销毁时,变量将被置为nil。
__unsafe_unretained很像__weak,但是当对象被释放时,指针不会被置为nil,指针会被随即赋值。
__autoreleasing,not to be confused with calling autorelease on an object before returning it from a method,this is used for passing objects by reference,for example when passing NSError objects by reference such as [myObject performOperationWithErro:@tmp];
Source:LLVM Clang Objective-C Automatic Reference Counting Documentation
NB:We have found @property declarations using 'retain' with ARC enabled(ie.instead of 'strong')do not cause compiler warnings and yield the same compiled result.This could change in future so stick to 'strong' fro clarify.
Migrating Existing Projects to ARC