1、ARC基本认识
ARC全称叫 ARC(Automatic ReferenceCounting),该机能在 iOS 5/ Mac OS X 10.7 开始导入,利用 Xcode4.2 可以使用该机能。
简单地理解ARC,就是通过指定的语法,让编译器(LLVM 3.0)在编译代码时,自动生成实例的引用计数管理部分代码。有一点,ARC并不是GC,它只是一种代码静态分析(Static Analyzer)工具。
1)使用ARC的好处
o 看到上面的例子,大家就知道了,以后写Objective-C的代码变得简单多了,因为我们不需要担心烦人的内存管理,担心内存泄露了
o 代码的总量变少了,看上去清爽了不少,也节省了劳动力
o 代码高速化,由于使用编译器管理引用计数,减少了低效代码的可能性
o 记住一堆新的ARC规则 — 关键字及特性等需要一定的学习周期
o 一些旧的代码,第三方代码使用的时候比较麻烦;修改代码需要工数,要么修改编译开关
关于第二点,由于XCode4.2 中缺省ARC就是 ON 的状态,所以编译旧代码的时候往往有"Automatic Reference Counting Issue"的错误信息。这个时候,可以将项目编译设置中的“Objectice-C Auto ReferenceCounteting”设为NO。
如果只想对某个.m文件不适应ARC,可以只针对该类文件加上-fno-objc-arc编译FLAGS。(与其对应的是-fobjc-arc)
o retain,release, autorelease, dealloc由编译器自动插入,不能在代码中调用
o dealloc虽然可以被重载,但是不能调用[super dealloc]
o 不能使用NSAllocateObject, NSDeallocateObject
o 不能在C结构体中使用对象指针
o id与void*间的如果cast时需要用特定的方法(__bridge关键字)
o 不能使用NSAutoReleasePool、而需要@autoreleasepool块
o 不能使用“new”开始的属性名称(如果使用会有下面的编译错误 “Property’s synthesized getter followsCocoa naming convention for returning ‘owned’ objects” )
由于ARC并不是GC,并需要一些规则让编译器支持代码插入,所以必须清楚清楚了这些规则后,才能写出健壮的代码。
5)对象处理的基本规则
o 只要对象的持有者存在(对象被强参照),那么就可以使用该对象
o 对象失去了持有者后,即被破弃
_strong
变量声明缺省都带有 _strong 关键字,如果变量什么关键字都不写,那么缺省就是强参照。
_weak
上面已经看到了,这是弱参照的关键字。该概念是新特性,从 iOS 5/ Mac OS X 10.7开始导入。由于该类型不影响对象的生命周期,所以如果对象之前就没有持有者,那么会出现刚创建就被破弃的问题,
弱参照还有一个特征,即当参数对象失去所有者之后,变量会被自动付上nil (Zeroing)。
_unsafe_unretained
该关键字与 _weak 一样,也是弱参照,与 _weak 的区别只是是否执行nil赋值(Zeroing)。但是这样,需要注意变量所指的对象已经被破弃了,地址却还存在,但内存中对象已经没有了。如果还是访问该对象,将引起「BAD_ACCESS」错误。
_autoreleasing
该关键字使对像延迟释放。比如你想传一个未初始化的对像引用到一个方法当中,在此方法中实例化此对像,那么这种情况可以使用 _autoreleasing 。他被经常用于函数有值参数返回时的处理,或者函数的返回值是在函数中申请的,那么希望释放是在调用端。
2、ARC对@property的使用规则影响
我们先来看看与所有权有关系的属性,关键字间的对应关系。
属性值 |
关键字 |
所有权 |
strong
|
_strong |
有 |
weak
|
_weak | 无 |
unsafe_unretained
|
_unsafe_unretained |
无 |
copy
|
_strong |
有 |
assign
|
_unsafe_unretained |
无 |
retain
|
_strong |
有 |
strong
该属性值对应 __strong 关键字,即该属性所声明的变量将成为对象的持有者。
weak
该属性对应 _weak 关键字,与_weak 定义的变量一致,该属性所声明的变量将没有对象的所有权,并且当对象被破弃之后,对象将被自动赋值nil。
并且,delegate 和 Outlet 应该用 weak 属性来声明。同时,如上一回介绍的 iOS 5 之前的版本是没有 _weak 关键字的,所以 weak 属性是不能使用的。这种情况我们使用 unsafe_unretained。
unsafe_unretained
等效于_unsafe_unretaind关键字声明的变量;像上面说明的,iOS 5之前的系统用该属性代替 weak 来使用。
copy
与 strong 的区别是声明变量是拷贝对象的持有者。
assign
一般Scalar Varible用该属性声明,比如,int, BOOL。
retain
该属性与 strong 一致;只是可读性更强一些。
比如下面的变量声明:
@property (nonatomic, readonly) NSString *name;
一般声明为 readonly 的变量按理说应该不需要持有所有权了,但是在ARC有效的情况下,将出现下面的错误信息 :
“ARC forbids synthesizing a property of anObjective-C object with unspecified ownership or storage attribute”
如果定义了ARC有效,那么必须要有所有者属性的定义;所以我们的代码改成这样,就OK了:
@property (nonatomic, strong, readonly) NSString *name;
不过有一点,Scalar Varible的变量缺省都有 assign 的属性定义,所以不需要给他们单独的明示声明了。
Objective-C中内存管理的方式其实就是指 引用计数 (Reference Counting)的使用准则:对象生成的时候必定被某个持有者拿着,如果有多个持有者的话,其引用计数就会递增;相反失去一个持有者那么引用计数即会递减,直到失去所有的持有者,才真正地从内测中释放自己。
1)内存管理的依循的基本原则
o 自己生成的对象,那么既是其持有者
o 不是自己生成的对象,也可成为其持有者(一个对象可以被多个人持有)
o 如果不想持有对象的时候,必须释放其所有权
o 不能释放已不再持有所有权的对象
结合 Objective-C 语言中的方法,我们来看看基本的内存管理。
方法 |
动作 |
alloc/new/copy/mutableCopy |
生成对象并拥有所有权 |
retain |
拥有对象所有权 |
release |
释放对象所有权 |
dealloc |
释放对象资源 |
Objective-C语言内部严格遵守上面表格中的定义;首先是alloc/new/copy/mutableCopy 这几个函数,并且是alloc/new/copy/mutableCopy 开头的函数,比如:allpcMyObject/newTheObject/copyThis/mutableCopyTheObject等都必须遵循这个原则。
如果不是 alloc/new/copy/mutableCopy开头的函数,而且要返回对象的话,那么调用端只是生成对象,而不是其持有者。