引用计数
引用计数规则
自己生成的对象 自己持有
使用以下名称开头的方法名,意味自己生成的对象只有自己持有:
- alloc
- new
- copy
- mutableCopy
id obj = [[NSObject alloc] init]
id obj = [NSObject new]
自己生成并持有对象,指向生成并持有对象的指针被复制给变量obj
非自己生成的对象 自己也能持有
用上面👆所述的几个方法之外取得的对象,因为是非自己生成并持有的,所以自己并不是对象的持有者
//取得的对象存在 但是自己并不持有该对象
id obj = [NSMutableArray array]
//自己持有该对象
[obj retain]
通过retain
方法 非自己生成的对象跟用alloc/new/copy/mutablecopy
一样,称为自己持有的对象
不再需要自己持有的对象时释放
自己持有的对象,一旦不再需要,持有者有义务释放该对象,释放使用release
方法
自己生成并持有对象 自己释放
//自己生成并持有对象 id obj = [[NSObject alloc] init]
//释放对象
[obj release]
/*
* 释放对象
* 指向对象的指针仍然被保留在变量obj中,貌似能够访问
* 但对象一经释放绝对不可访问
*/非自己生成并持有的对象 也可以通过
release
释放//取的对象 但是自己并不持有 id obj = [[NSObject alloc] init]
//自己持有对象
[obj retain]
//释放对象
[obj release]用retian方法持有的对象 一旦不再寻妖 务必用
release
方法进行释放调用
alloc/new/copy/mutablecopy
开头方法生成对象,并将其返回该方法调用方-(id)allocObject { //自己生成并且持有对象
id obj = [[NSObject alloc] init]
return obj
}
//自己持有对象
id obj1 = [obj0 allocObject]原封不动的返回alloc方法生成并且持有的对象 就能让调用方也持有该对象
allocObject
是符合前面的命名规则的 因此调用该方法也能自己生成并且持有该对象调用非
alloc/new/copy/mutablecopy
开头方法生成对象此类型的方法 就是我们常用的
[NSArray array]
方法类似-(id)object { //自己生成并持有对象
id obj = [[NSObject alloc] init]
//取得对象存在 但自己不持有对象
[obj autorelease]
//返回对象
return obj
}
//取得的对象存在 但是自己不持有对象
id obj1 = [obj0 object]
//自己持有对象
[obj1 retain]使用
autorelease
方法,可以取得对象存在,但自己不持有对象。
autorelease
,使对象在超出指定生存范围时 能自动并且正确释放注意
这些谁都不持有的对象的方法名不能以
alloc/new/copy/mutablecopy
开头
无法释放非自己持有的对象
用alloc/new/copy/mutablecopy
开头获得的对象 或者 retain
方法持有的对象 持有者是自己
当持有者是自己时 在不需要的时候将其释放 除此之外,得到的而对象绝对不能释放
alloc/retain/release/dealloc实现过程
GUNStep中的实现方式
用alloc类方法初始化对象时,初始化开辟内存大小为对象大小加上一个 记录引用计数的结构体大小的空间。
用该结构体中的retained
整数来保存引用计数,并将其写到对象内存头部。通过对该结构体中的数值进行操作,来获取、增加、减少引用数值
- 在
Object-C
对象存有引用计数这一数值 - 调用alloc方法或retain方法 引用计数加1
- 调用release后 引用计数减1
- 引用计数为0 调用dealloc方法废弃该对象
苹果的实现
在NSObject
类方法上设置断点,列出alloc
方法执行的函数
+alloc
+allocWithZone
class_creatInstance
calloc
alloc方法先调用+allocWithZone
方法,然后调用运行时中的class_createInstance
函数,最后调用calloc
来分配内存块
retaincount/retain/release
操作的实现 apple是维护了以个散列表(引用计数表)来管理引用计数
散列表中 键值为内存块地址的散列值
autorelease
autorelease
像C语言的自动变量那样来对待对象实例,当超出作用域,对象实例release方法被调用,编程人员可以设定变量的作用域
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]
id obj = [[NSObject alloc] init]
[obj autorelease]
//等效于执行了 [obj release]
[pool drain]
在Cocoa框架中,相当于程序主循环的NSRunLoop
或者在其他程序可运行的地方,对NSAutoreleasePool
对象进行生成,持有和废弃处理。因此,程序开发者不一定非要使用NSAutoreleasePool
对象进行开发处理工作
注意:
虽然runloop会自动废弃
NSRunloop
对象,但是在大量产生对象时 也会产生内存不足的现象,需要在使用完后,手动及时释放对象
在cocoa框架中,很多类方法 用于返回autorelease对象
id array = [NSMutableArray arrayWithCapacity:1];
//相当于以下源代码
id array = [[NSMutableArray arrayWithCapacity:1] autorelease];
注意
在OC中 也就是Foundation框架时,无论调用那一个对象的autorelease方法,实现上是调用NSObject类的autorelease实例方法。但是对于NSAutoreleasePool类,该方法已经被重载,因此运行时会报错