什么是ARC?
官方给出的解释是:Automatic Reference Counting (ARC) is a compiler feature that provides automatic memory management of Objective-C objects. Rather than having to think about retain and release operations, ARC allows you to concentrate on the interesting code, the object graphs, and the relationships between objects in your application.
自动引用计数是一种编译器特性,提供对象的自动内存管理。ARC使得你能够专一于你的应用中的代码,UI以及对象之间的关系而不须要去关心使用retain、release去进行繁冗的内存管理。html
ARC经过增长编译时代码确保对象按需存在,按需释放。概念上来讲,它与手动引用计数(MRC)听从一样的规则:为你添加正确适当的内存管理代码。为了确保编译器生成正确的代码,ARC限制了你可使用的方法和你使用toll-tree bridging的方式。Toll-free bridging,简称为TFB,是一种容许某些ObjC类与其对应的CoreFoundation类之间能够互换使用的机制。关于Toll-free bridging能够搜索官方文档,这里给出一篇推荐博文:清风徐来,水波不兴。程序员
ARC的支持:Xcode4.2以上,OS X v10.7以上,IOS5以上。能够参考官方原句:ARC is supported in Xcode 4.2 for OS X v10.6 and v10.7 (64-bit applications) and for iOS4 and iOS5.Weak references are not supported in OS X v10.6 and iOS 4.
编程
ARC与MRC的区别及编程方式
MRC : Manual Reference Counting。使用retain来增长内存的引用计数,release来减小引用计数,autorelease来加入自动释放池等等。
ARC : Automatic Reference Counting。自动引用计数,毫不能再出现以上的三个关键字,实际上Xcode也会报错。app
使用ARC须要遵循的新规则:
为了正确的工做,ARC规定了一些其余编译模式没有的新规则。这些规则旨在提供一个彻底可信的内存管理模型,在一些状况下,他们仅执行最佳实践,而另外一些状况下,他们简化你的代码或者明显的告知你不须要处理内存管理。若是你违反了这些规则,你会获得一个明显的编译时错误,而不是一个微小的错误可是在运行时却有可能成为一个大问题,问题能够及早的暴漏出来,而不是在程序有bug的时候再去苦苦的找bug,因此说ARC简直是程序员的福音。相比之下,仍是遵照下面的这些规则比较简单:
ide
1 . 不能显式调用dealloc,retain,release,retainCount,autorelease,或者是使用@selector(retain),@selector(release)等等。可是你能够若是你须要释放一些资源而不是释放实例变量时,你能够实现dealloc,在dealloc函数里面去完成这些工做,可是记住,不要去调用,由于编译器会帮你作的。同时,dealloc函数里也不要去调用super dealloa,这也是编译器的工做。可是你可能须要在系统类和其余未使用ARC的代码中调用[systemClassInstance setDelegate:nil] ,同时你也须要使用CFRetain,CFRelease和其余CoreFoundation对象的相关方法。理解了Toll-free bridging你或许会清楚这个问题。函数
2 . 不能使用NSAllocateObject或者NSDeallocateObject。使用alloc建立对象,系统在运行时会关注对象的生存周期并在适当的时候释放他。ui
3 . 不能在C结构体中使用对象指针。若是你要使用结构体,还不如直接创建一个Objective-C对象来管理数据。spa
4 . id与void *之间不能随意的转换。你必须使用特定的类型转换告诉编译器对象的生命周期,在Objective-C对象与做为函数传入参数的CoreFoundation对象之间你须要作这样的转换。翻译
5 . 不能使用NSAutoreleasePool自动释放池。ARC提供@autoreleasepool代替,而且比NSAutoreleasePool更高效。设计
6 . 不能使用内存区(memmory zons)。再也没有必要使用NSZone,由于现代的Objective-C运行时会忽略它。
7 . 不能以new为开头去命名一个访问器,这意味着你不能声明一个以new开头的property,除非你附给他一个不一样名字的getter:
@property NSString *newTitle; //错误的
@property (getter=theNewTitle) NSString *newTitle; //正确的
ARC的编程方式
ARC引入了新的对象生命周期修饰符和弱引用。weak reference弱引用不会增长它所指向的对象的引用计数,并且当它所指向的对象引用计数变为0时会自动的变成nil,这样咱们不用担忧会指向已经释放的内存,EXC_BAD_ACCESS错误也会减小不少。你也能够充分使用这些修饰符来管理你的程序中的对象,好比说,ARC没法避免强循环引用,可是你能够巧妙的使用weak修饰符来确保你的程序不会有循环引用。
weak和strong是新引入的属性修饰符,例子以下:
1 @property(strong) MyClass *myObject; //强引用,同retain 2 @property(weak) MyClass *myObject; //弱引用,同assign,当所指向的对象被释放后被自动的置为nil
在ARC的工程中,strong是对象的默认属性,可是为了不歧义最好仍是显式的指明。
变量修饰符:
上面介绍了属性修饰符,下面来看看这几款变量修饰符。const你必定使用过,相似的变量修饰符还有这些:
__strong
__weak
__unsafe_unretained
__autoreleasing
__strong:缺省的修饰符,当对象有strong指针指向他时,他是不被释放的,alive。
__weak:保留对对象的弱引用指针,不增长引用计数,所以也对对象的生命周期没有保障,当所指向的对象被释放后自动置为nil。
__unsafe_unretained:保留对象的弱引用指针,当所指向的对象被释放后,该指针不会被置为nil,变成野指针。
__autoreleasing:修饰以引用(id *)传入的参数,而且当return后会被自动释放。主要用于引用传入参数。
变量修饰符的使用格式:
ClassName * qualifier variableName;
例如:
MyClass * __weak myWeakReference; MyClass * __unsafe_unretained myUnsafeReference;
虽然说编译器很伟大但偶尔也会小粗心一下,例以下面的错误就不会被报错,只是小警告,因此不要忽略警告哦~下面的例子是错误示例:
NSString * __weak string = [[NSString alloc] initWithFormat:@"First Name: %@", [self firstName]]; NSLog(@"string: %@", string);
虽然string在刚建立并初始化完成后使用,可是并无一个强指针指向该对象,所以他一初始化完成就因为引用计数为0被释放了。结果输出的是null,缘由你懂的,上面说过三遍。
经过引用传入的对象也须要注意,下面的例子是正确的:
-(BOOL)performOperationWithError:(NSError * __autoreleasing *)error;
NSError *error; BOOL OK = [myObject performOperationWithError:&error]; if (!OK) { //use }
编译器会将代码补全为以下:
1 NSError * __strong error; 2 NSError * __autoreleasing tmp = error; 3 BOOL OK = [myObject performOperationWithError:&tmp]; 4 error = tmp; 5 if (!OK) { 6 //use 7 }
以__autoreleasing声明参数实际上是告诉ARC编译器,这个函数没有这个对象的拥有权,因此在函数里面的read和write该引用所指向的对象时,就将它放到自动释放池吧,return后就释放掉,固然这些是编译器作的事。官方文档告诉咱们:传入的本地变量为__strong(默认的)与形参__autoreleasing不匹配致使了编译器会生成一个临时变量tmp,你能够像以上这样作,声明参数为__autoreleasing,同时也能够经过将参数声明为id __strong *来得到__strong变量的地址。(如今尚没有想清楚这两种有什么区别)
ARC中如何避免循环引用?
你可使用对象的生命周期修饰符来避免强引用循环而致使的互相引用内存不能被释放,从而形成内存泄露。例如,你能够设计一个父子对象图,父对象对子对象能够强引用strong,同时子对象对父对象的引用为弱类型的引用weak。
巧妙的使用weak弱引用是避免循环引用的良药,这就是一般为何delegate为弱类型的缘由。另外最容易循环引用的一块就是block内对自身的属性引用,这又是另一块很重要的问题,将在后续的博客中单独做为一篇来说解。
如何将设置工程为ARC?
1.新建ARC工程
新的编译器新建的工程默认支持ARC,查看Objective-C Automatic Reference Counting选项,YES表示支持ARC。
2.将旧MRC工程转化为ARC
(1)首先查看编译器是否支持,若是不支持选择编译器或者升级编译器,记住ARC是LLVM 3.0及之后的新特性,以前的编译器不支持,若是你的Compiler选项还在以前,那赶忙升级Xcode吧,不然新时代已经不适合你咯~按照下面的图示选择便可,个人Xcode是5.0的,编译器也是5.0。
(2)一样是在Build Settings里面,将Objective-C Automatic Reference Counting选项改成YES,以下:
(3)run一下工程吧,不少错误吧,一个一个改正吧~按照咱们前面提到的ARC的规则,将一些retain,release等相关MRC字段都改成ARC规则的,将一些property属性,retain改成strong,assign改成weak,不能显示调用dealloc函数等等,记住一些基础类型如BOOL等仍是assign。对于一个小工程来讲手动修改很容易,可是工程很大就比较费脑筋了,幸好伟大的Xcode提供了自动转换到ARC的功能。具体就再也不细说,能够参考这个牛人的博客里面的例子:人淡如菊,讲的已经很是详细。同时也会有些非ARC的第三方库那就直接将库设置编译属性为非ARC吧,不要去修改库了。另外,Core Foundation的一些东西也会牵扯到桥接的内容,后续博客再详细介绍。
3.设置ARC工程中兼容MRC的文件
在工程的Build Phases中的Compile Sources选项中找到对应的.m文件,将其Compiler Flags设置为-fobjc-arc,这样单个文件就支持ARC了。而若是ARC的工程中里,想要设置某个单个文件不支持ARC,一样的操做步骤,将其Compiler Flags设置为-fno-objc-arc。
一些推荐阅读的内容:
官方ARC文档(英文的,本篇博客大部分都翻译于此,另外也有些ARC相关的重要内容,后续我会继续翻译)
OneV's Den的这篇文章(很详细,耐着性子看完会颇有收获)
Clang 3.0 Document (超长哦,是我翻译的目标)
声明:本博客所有本身手动整理,翻译了官方博客,而且用本身的话整理了一些内容,若有问题,请在下面回复,谢谢!