天天看点

【Objective-C】引用计数一.基本概念:二.内存管理的思考方式:

一.基本概念:

自动引用计数(ARC,Automatic Reference Counting)是指内存管理中对引用采取自动计数的技术;苹果官方说明:

在Objective-C中采用Automatic Reference Counting(ARC)机制,让编译器来进行内存管理。在新一代Apple LLVM编译器中设置ARC为有效状态,就无需再次键入retain或者release代码,这就降低程序崩溃、内存泄露等风险的同时,很大程度上减少了开发程序的工作量。编译器完全清除目标对象,并能立刻释放那些不再被使用的对象。如此一来,引用程序具有可预防性,且能流畅运行,速度也将大幅提升。

当一个对象的引用计数为大于0的计数,表示这个对象被持有,不能被释放,当引用计数为0时表示这个对象需要被释放掉。

什么是引用计数?

引用计数的原理:引用计数可以有效的管理对象的生命周期,当我们创建一个新对象的时候,它(该对象所在的内存块)的引用计数为1,当有一个新的指针指向这个对象时,我们将其引用计数加1,当某个指针不在指向这个地址时,我们将其应用计数减1,当对象的引用计数变为0时,说明这块内存不在被任何指针指向,这个时候系统就会将对象销毁,回收内存。从而达到管理内存的目的。

举例说明:

在晚上办公的时候,如果办公室有人的话就需要开灯,没人的话就不需要开灯,引用计数就如此一般,办公室就相当于该对象,办公室中的人数就相当于该对象的引用计数,来一个人该办公室的引用计数就的加一,走一个人就的减一,只要办公室有人这个灯就得开,没人的时候就可以关掉,相当于释放这个对象。

对办公室照明设备所做的动作和对Objective-C对象所做的动作:

对照明设备所做的动作 对Objective-C对象所做的动作
开灯 生成对象
需要照明 持有对象
不需要照明 释放对象
关灯 废弃对象

二.内存管理的思考方式:

对象操作与Objective-C方法的对应:

对象操作 Objective-C
生成并持有对象 alloc/new/copy/mutableCopy 等方法
持有对象 retain 方法
释放对象 relea 方法
废弃对象 dealloc 方法

自己生成的对象,自己持有

使用

alloc

new

copy

mutableCopy

开头的方法名意味着自己生成的对象只有自己持有。

例如:

id obj = [[NSObject alloc] init];

id obj = [NSObject new];
           

其中

[[NSObject alloc] init]

[NSObject new]

是完全一致的。

命名规则:驼峰命名法

另外,根据上述“使用以下名称开头的方法名”,下列名称也意味着自己生成并持有对象。

  • allocMyObject
  • newThatObject
  • copyThis
  • mutableCopyYourObject

但是对于以下名称,即使用

alloc/new/copy/mutableCopy

名称开头,并不属于同一类别方法。

  • allocate
  • newer
  • copying
  • mutableCopyed

非自己生成的对象,自己也能持有

使用上述方法以外的方法来获取对象,即使用

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];
//释放了非自己持有的对象!
//这肯定会导致应用程序崩溃!