什么是自动引用计数?
自动引用计数(ARC,Automatic Reference Counting)是指内存管理中对引用采取自动计数的技术。
内存管理的思考方式
- 自己生成的对象,自己持有。
- 非自己生成的对象,自己也能持有。
- 不再需要自己持有的对象时释放。
- 非自己持有的对象无法释放。
自己生成的对象,自己持有
使用以下名称开头的方法名意味着自己生成的对象自己持有:
- alloc
- new
- copy
- mutableCopy
另外,下列名称也意味着自己生成并持有对象。
- allocMyObject
- newThatObject
- copyThis
- mutableCopyYourObject
1 | /** 自己生成并持有对象 */ |
使用[NSObject new]
与[[NSObject alloc] init]
是完全一致的。
1 | /** 自己生成并持有对象 */ |
非自己生成的对象,自己也能持有
用alloc/new/copy/mutableCopy以外的方法取得的对象,因为非自己生成并持有,所以自己不是该对象的持有者。
1 | /** 取得非自己生成并持有的对象 */ |
源代码中,NSMutableArray类对象被赋值给变量obj,但变量obj自己并不持有该对象,使用retain方法可以持有对象。
1 | /** 取得非自己生成并持有的对象 */ |
通过retain方法,非自己生成的对象跟用 alloc/new/copy/mutableCopy 方法生成并持有的对象一样,成为了自己所持有的。
不再需要自己持有的对象时释放
自己持有的对象,一旦不再需要,持有者有义务释放该对象,释放使用release方法。
1 | /** 自己生成并持有对象 */ |
用alloc方法由自己生成并持有的对象就通过release方法释放了。自己生成而非自己所持有的对象,若用retain方法变为自己持有,也同样可以用release方法释放。
1 | /** 取得非自己生成并持有的对象 */ |
用 alloc/new/copy/mutableCopy 方法生成并持有的对象,或者用retain方法持有的对象,一旦不再需要,务必要用release方法进行释放。
如果要用某个方法生成对象,并将其返回给该方法的调用方,那么它的源代码又是如何呢?
1 | -(id)allocObject { |
如上例所示,原封不动的返回alloc方法生成并持有的对象,就能让调用方也持有该对象。请注意allocObject这个名称是符合前文命名规则的。
1 | /** 取得非自己生成并持有的对象 */ |
allocObject名称符合前文的命名规则,因此它与用alloc方法生成并持有对象的情况完全相同,所以使用allocObject方法也意味着”自己生成并持有对象”。
那么,调用[NSMutable array]方法使取得的对象存在,但自己不持有对象,又是如何实现的呢?根据上下文命名规则,不能使用alloc/new/copy/mutableCopy 开头的方法名,因此要使用object这个方法名。
1 | - (id)object { |
上例中,我们使用了autorelease方法。用该方法可以使取得的对象存在,但自己不持有对象。autorelease 提供这样的功能,使对象在超出指定的生存范围时,能够自动并正确地释放(调用release 方法)。
使用NSMutableArray类的array类方法等可以取得谁都不持有的对象,这些方法都是通过 autorelease 而实现的。此外,根据上下文的命名规则,这些用来取得谁都不持有的对象的方法名不能以alloc/new/copy/mutableCopy 开头。
1 | id obj1 = [obj0 object]; |
当然也可以通过 retain 方法将调用 autorelease 方法取得的对象变为自己持有。
1 | id obj1 = [obj0 object]; |
非自己持有的对象无法释放
对于用 alloc/new/copy/mutableCopy 方法生成并持有的对象,或是用 retain 方法持有的对象,由于持有者是自己,所以在不需要该对象时需要将其释放。而由此外得到的对象绝对不能释放。倘若在应用程序中释放了非自己持有的对象就会造成崩溃。
例如自己生成并持有对象后,在释放完不再需要的对象之后再次释放。
1 | /** 自己生成并持有对象 */ |
或者在”取得的对象存在,但自己不持有对象”时释放。
1 | id obj1 = [obj0 object]; |
参考链接
《iOS与OS X多线程和内存管理》