自动引用计数(ARC, Automatic Reference Counting)是指内存管理中对引用计数采取自动计数的技术。
在ARC中,编译器会自动在适当的地方插入retain、release和autorelease操作,以便正确地管理对象的生命周期。这样,开发者可以在不显式编写内存管理代码的情况下,有效地管理对象的引用计数。
在ARC下,开发者不需要手动调用retain、release和autorelease方法,也不需要实现dealloc方法。相反,编译器会在编译时分析代码,并根据对象的引用关系自动插入内存管理代码。
在Objective-C中通过引用计数来实现内存管理,当对象的引用计数大于1时表示这个对象被持有,当对象的引用计数为0时表示这个对象被废弃。
那么是谁来持有对象呢?这里就要引入对象的使用环境了。对象的使用环境通过某些特定方法生成并持有对象,成为对象的持有者。也可以通过某种方法释放对象,最后通过某种方法废弃对象。对象的使用环境有时也指在运行中的程序代码、变量、变量作用域、对象等,但在概念上就是使用对象的环境。
引用计数式内存管理的思考方式如下:
下面时内存管理的思考方式中出现的各个项目
使用下面名称开头的方法名意味着自己生成的对象自己持有:
//自己生成并持有对象
id obj1 = [[NSObject alloc] init];
//自己生成并持有对象
id obj2 = [NSObject new];
使用copy方法需要遵循NSCopying协议并实现协议里的copyWithZone:方法生成并持有对象的不可变副本。使用mutableCopy方法需遵循NSMutableCopying协议并实现协议里的mutableCopyWithZone:方法生成并持有对象的可变副本。
根据上面“使用以下名称开头的方法名”下列名称也意味着自己生成并持有对象。
但是对于以下名称,也使用alloc/new/copy/mutableCopy名称开头,并不属于同一类别方法
使用上述方法以外的方法来获取对象,即使用alloc/new/copy/mutableCopy以外的方法取得的对象,因为非自己生成并持有,所以自己不是该对象的持有者。
//获取非自己生成并持有的对象
id obj = [NSMutableArray array];
//获取到了对象,但是自己并不持有
//自己持有对象
[obj retain];
通过retain方法,非自己持有生成的对象跟用alloc/new/copy/mutableCopy方法生成并持有的对象一样,成了自己所持有的。
自己持有的对象,一旦不再需要,持有者有义务释放该对象,释放使用release方法。
//自己生成并持有对象
id obj = [[NSObject alloc] init];
//释放对象
[obj release];
注意:指向对象的指针仍然被保留在变量obj中,貌似能够访问,但对象一经释放绝对不可访问。
同样,自己生成而非自己所持有的对象,若使用retain方法持有,同样也可以使用release释放。
//获取非自己生成并持有的对象
id obj = [NSMutableArray array];
//获取到了对象,但是自己并不持有
//自己持有对象
[obj retain];
//释放对象,对象不可再被访问
[obj release];
用alloc/new/copy/mutableCopy方法生成并持有的对象,或者用retain方法持有的对象,一旦不再需要,务必要用release方法进行释放。
- (id)allocObject {
//自己生成并持有对象
id obj = [[NSObject alloc] init];
return obj;
}
//调用上边的方法,也可以取得非自己生成并持有的对象
id obj1 = [obj0 allocObject];
- (id)object {
//自己生成并持有对象
id obj = [[NSObject alloc] init];
//取得的对象存在,但自己并不持有
[obj autorelease];
return obj;
}
//调用上边的方法,可以取得的对象存在,但是并不持有
id obj1 = [obj0 object];
使用了autorelease方法可以使取得的对象存在,但自己不持有对象。autorelease提供这样的功能,使对象在超出指定的生存范围时能够自动并正确的释放(调用release方法)。
对于用alloc/new/copy/mutableCopy方法生成并持有的对象,或者用retain方法持有的对象,由于持有者是自己,所以在不需要该对象时需要将其释放。而由此以外所得到的对象绝对不能释放。倘若在应用程序中释放了非自己持有的对象就会造成崩溃。例如自己生成并持有对象后,在释放完不再需要的对象之后再次释放。
//自己生成并持有对象
id obj = [[NSObject alloc] init];
//释放对象
[obj release];
//释放之后再次释放已非自己持有的对象,应用程序崩溃!
[obj release];
//崩溃情况:
//再度废弃已经废弃了的对象时崩溃,访问已经废弃的对象时崩溃
在“取得的对象存在,但自己不持有对象”时释放。
- (id)object {
//自己生成并持有对象
id obj = [[NSObject alloc] init];
//取得的对象存在,但自己并不持有
[obj autorelease];
return obj;
}
//调用上边的方法,可以取得的对象存在,但是并不持有
id obj1 = [obj0 object];
[obj1 release];
//释放了非自己持有的对象!
//这肯定会导致应用程序崩溃!