内存管理
内存管理其实就是对引用计数的管理,需要从MRC和ARC两方面探讨,其中MRC与ARC的主要区别是MRC下需要手动retain、release、autorelease等在ARC下会自动完成。
1、引用计数相关操作
对象操作 | OC中对应的方法 | 对应的 retainCount 变化 |
---|---|---|
生成并持有对象 | alloc/new/copy/mutableCopy等 | +1 |
持有对象 | retain | +1 |
释放对象 | release | -1 |
释放对象 | dealloc | 0 |
alloc
struct objc_layout{
NSUInteger retained;
};
+(id)alloc
{
int size = sizeof(struct objc_layout) + 对象大小;
struct objc_layout *p = (struct objc_layout *)calloc(1, size);
//1.calloc在动态分配完内存后,自动初始化该内存空间为零,而malloc不初始化,里边数据是随机的垃圾数据。
//2.struct objc_layout存放引用计数,开辟一个struct objc_layout结构大小加对象大小的内存,并用一个struct objc_layout指针指向该内存。
return (id) (p+1) ;
//p是struct objc_layout指针,p+1后指针则指向存放对象的内存
}
retain
+(id)retain
{
if (((struct objc_layout *)self)[-1].retained == UINT_MAX - 1)
[NSException raise:NSInternalInconsistencyException format:@"NSIncrementExtraRefCount() asked to increment to far"]; //当retaind变量超出最大值时抛出异常
((struct objc_layout *)self)[-1].retained ++;//引用计数加1
}
//这里[-1]其实是拿到对象前面的引用计数的下标
//因为[0]是此对象的下标
release
+ (void)release{
if (((struct objc_layout *)self)[-1].retained == 0) {
[self dealloc]; //引用计数为0 释放对象
}else{
((struct objc_layout *)self)[-1].retained--; //引用计数减1
}
}
dealloc
+ (void) dealloc
{
struct objc_layout *o = &((struct objc_layout *)self)[-1];
free(o);
}
2、内存管理规则
3、几种生成与持有对象的情况
//自己生成对象并持有对象
id obj0 = [[NSObject alloc] init];
id obj1 = [NSObject new];
//自己不生成对象但是持有对象,但是对象存在
id obj0 = [NSArray array]
[obj0 retain]
id obj0 = [[NSObject alloc] init];
id obj1 = [NSObject new]; //生成并持有对象
[obj0 release] //释放对象
[obj1 release] //释放对象
id obj0 = [NSArray array]
//自己不生成对象, 但是对象存在
[obj0 release]
//会出错,因为它不持有这个对象,但是又给它发送了release