文章目录
什么是自动引用计数
自动引用计数(ARC,Automatic Reference Counting)是指内存管理中对引用采取自动计数的技术。用苹果官方说明的话说:
在OC中采用ARC机制,让编译器来进行内存管理,在新一代Apple LLVM编译器中设置ARC为有效状态,就无需再键入retain或者release代码。
也就是说,只要满足以下条件,就无需手动输入retain和release代码了:
-
使用Xcode4.2或以上版本
-
使用LLVM编译器3.0或以上版本
-
编译器选项中设置ARC为有效
在以上条件下编译源代码时,编译器将自动进行内存管理。接下来我们先了解一下在ARC之前,程序员是如何手动进行内存管理的
内存管理/引用计数
概要
OC中的内存管理,也就是引用计数,可以用开关房间的灯为例来说明引用计数的机制。
假设办公室里只有一个照明设备,上班进入办公室的人需要照明,所以把灯打开。而对于下班离开的人来说,已经不需要照明了,所以要把灯关掉。但是,并不是每个人都需要进行开关灯的操作的,只要第一个人开了灯,后面的人就不必再开灯了,关灯也必须是最后一个离开的人关灯。所以为了判断办公室里还有多少人,我们就引入一个计数来统计需要照明的人数。
(1)第一个人进来,人数加一,计数从零变成一,因此要开灯
(2)之后每进来一个人,人数就加一
(3)每当有人下班离开,人数就减一
(4)最后一个人离开时,人数减一,计数从一变成零,因此要关灯
在OC中,"对象"就相当于照明设备,"对象的使用环境"就相当于上班进入办公室的人。上班时发出的动作与OC中的对应关系如下表:
OC的内存管理就是基于这个逻辑实现的
内存管理的思考方式
有关于引用计数,正确的思考方式有四条准则:
-
自己生成的对象,自己所持有
-
非自己生成的对象,自己也能持有
-
不再需要自己持有的对象时释放
-
非自己持有的对象无法释放
这就是引用计数式内存管理的思考方式,而在OC的内存管理中,除了"生成"、"持有"、"释放"三个词以外,还要加上"废弃",这四个词组成了OC内存管理的基本操作
相对应的方法如下表所示:
这些有关内存管理的方法,包含在Cocoa框架中用于OS X、iOS应用开发。Cocoa框架中Foundation框架类库的NSObject类担负内存管理的职责。OC内存管理中的alloc/retain/release/dealoc方法分别指代NSObject类的alloc类方法、retain实例方法、release示例方法和dealloc实例方法
接下来我们详细了解内存管理的思考方式中的各个项目
自己生成的对象,自己所持有
使用以下名称开头的方法名意味着自己生成的对象只有自己持有:
-
alloc
-
new
-
copy
-
mutableCopy
下面写出自己生成并持有对象的源代码,为生成并持有对象,我们使用alloc方法。
objectivec
// 自己生成并持有对象
id obj = [[NSobject alloc] init];
使用NSObject的类方法就能自己生成并持有对象,指向生成并持有对象的指针被赋给变量obj。另外,使用new类方法也能生成并持有对象。
copy方法基于NSCopying方法约定,由各类实现的copyWithZone:方法生成并持有对象的副本,mutableCopy也一样,二者区别只在于生成的对象是否可变。这些方法生成的对象,虽然是对象的副本,但也属于"自己生成并持有对象"。
此外,根据上述"使用以下名称开头的方法名",下列名称也意味着自己生成并持有对象
-
allocMyObject
-
newThatObject
-
copyThis
-
mutableCopyYourObject
但以下名称,并不属于同一类别的方法
-
allocate
-
newer
-
copying
-
mutableCopyed
非自己生成的对象,自己也能持有
用上述项目之外的方法(即alloc/new/copy/mutableCopy以外的方法)取得的对象,因为非自己生成并持有,所以自己不是该对象的持有者。
objectivec
//取得非自己生成并持有的对象
id obj = [NSMutableArray array];
//取得的对象存在,但自己不持有对象
这段代码中,NSMutableArray类对象被赋给变量obj,但变量obj自己并不持有该对象,使用retain方法可以持有对象
objectivec
//取得非自己生成并持有的对象
id obj = [NSMutableArray array];
//取得的对象存在,但自己不持有对象
[obj retain];
//自己持有对象
通过retain方法,可以将对象变为自己所持有的
不再需要自己持有的对象时释放
自己持有的对象,一旦不再需要时,持有者有义务释放该对象,使用release方法
objectivec
id obj = [[NSObject alloc] init];
[obj release];
//释放对象
指向对象的指针仍然被保留在变量obj中,貌似能够访问
但对象一经释放绝对不可访问
这样,对象就被release方法释放了,自己生成而非自己持有的对象,如果用retain变成自己持有,同样可以用release释放
用alloc/new/copy/mutableCopy方法生成并持有的对象,或者用retain方法持有的对象,一旦不再需要,务必用release释放。
如果要用某个方法生成对象,并将其返还给该方法调用方,源代码如下:
objectivec
- (id)allocObject {
id obj = [[NSObject alloc] init];
return obj;
}
如上例,将用alloc方法生成的对象直接返回。就能让调用方也持有该对象。
注意,这里与上文命名规则相符合,使用allocObject也就意味着"自己生成并持有对象"
那像[NSMutableArray array]这种方法使取得的对象存在,但自己不持有对象,又是如何实现的呢?根据上文规则,不能使用alloc/new/copy/mutableCopy开头的方法名,因此我们使用object这个方法名
objectivec
- (id)object {
id obj = [[NSObject alloc] init];
[obj autorelease];
//取得对象存在,但自己不持有对象
return obj;
}
上例中,我们使用了autorelease方法,用这个方法可以使取得的对象存在,但自己不持有对象,autorelease提供这种功能,是对象在超出指定生存范围时能自动并正确的释放。
使用NSMutableArray类的array类方法可以取得谁都不持有的对象,这些方法都是通过autorelease来实现的。
无法释放非自己持有的对象
得到非自己持有的对象无法释放,倘若在应用程序中释放了非自己持有的对象就会造成崩溃。例如自己生成并持有对象后,在释放完不再需要的对象之后再次释放
objectivec
id obj = [[NSObject alloc] init];
[obj release];
[obj release];
//应用程序崩溃!
//访问已经废弃的对象时崩溃
或者"取得的对象存在,但自己不持有对象"时释放
objectivec
id obj1 = [obj0 object];
//取得对象存在,但自己不持有
[obj1 release];
//程序崩溃
以上就是"引用计数式内存管理"的思考方式