注:本文在每段代码中首段标有 "//ARC" 意为使用ARC的代码, "//MRC"则为MRC的代码
</br>
//ARC
+ (id) array {
return [[NSMutableArray alloc] init];
}
上面是NSMutableArray的类方法,�这样返回在ARC里面没有任何问题,因为编译器会自动替你完成工作。
现在假设我们在MRC的环境里:
//MRC
+ (id) array {
return [[NSMutableArray alloc] init];
}
这就有问题了,直接返回之后你没有办法释放alloc之后创建的对象(造成内存泄露)。对了,你没有一个指针对象可以访问到它,来做释放操作。你也许想到这么做:
//MRC
+ (id) array {
NSMutableArray *array = [[NSMutableArray alloc] init];
return array;
}
但这么做也不对啊。虽说有一个指针可以访问并释放它了,但它是在return前释放也不是,在return后释放就更不对了。
所有我们需要一种可以返回了这个对象,并在晚点再释放的机制——自动释放池(autoreleasepool)。
把返回的对象注册到autoreleasepool里面可以延迟释放,只要对其调用autorelease:
//MRC
+ (id) array {
return [[[NSMutableArray alloc] init] autorelease];
}
上面的代码等价于在ARC时:
//ARC
+ (id) array {
return [[NSMutableArray alloc] init];
}
autorelease的方法ARC已经帮你调用了,只是你看不到。
</br>
再回来看:
//ARC
id obj = [NSMutableArray array];
//等价于
id __strong obj = [NSMutableArray array];
在ARC里,对象默认是strong的,所以obj要持有对象,为了不让返回的对象自动释放,所以�会自动调用一次retain。相当于MRC如下代码:
//MRC
id temp = [NSMutableArray array];
id obj = [temp retain];
综上,ARC为我们自动调用了autorelease和retain这两个方法。
如果我们使用MRC实现,是否需要这么麻烦呢?你重翻看上面的代码就�发现,MRC不调用autorelease和retain方法,也实现了同样的事情。
所以调用跟不调用autorelease和retain这两个方法时的情况是一样的。ARC白白调用了2次多余的方法,又没有多干活,肯定影响性能。ARC这么傻,我为什么还要用它?ARC肯定采取了措施进行了优化。
因为直接将二者删去这种处理方式,又要考虑到“向后兼容性”问题,以兼容那些不使用ARC的代码。
所以ARC就使用objc_autoreleaseReturnValue和
objc_retainAutoreleasedReturnValue这两个函数对这些多余的操作进行优化。
</br>
在使用非alloc/new/copy/mutableCopy等开头生成对象的方法,都会调用这两个方法,比如array类方法会变成下面这样,objc_autoreleaseReturnValue函数替代了autorelease方法:
+ (id) array {
NSMutableArray *array = [[NSMutableArray alloc] init];
objc_autoreleaseReturnValue(array);
}
当在外部调用array方法赋值时方法是这样,
objc_retainAutoreleasedReturnValue函数替代了retain方法:
id temp = [NSMutable array];
id obj = objc_retainAutoreleasedReturnValue(temp);
如上代码所示,会先调用objc_autoreleaseReturnValue�函数,它的作用是检视稍后执行的代码是否会执行retain方法,如果有,会把某个专用于检测的变量,或者说数据结构的标志位置位,并直接返回对象(上例array),不执行autorelease方法;否则,对对象(上例array)执行autorelease方法。 objc_retainAutoreleasedReturnValue函数则是访问专用于检测的变量的标志位,看其是否有置位,如果有,直接返回对象;否则,对对象执行retain方法。查看一个标志位,一般都要比调用autorelease和retain来得快吧?
id objc_autoreleaseReturnValue(id object) {
if ( //调用者将会执行retain ) {
set_flag(object);
return object;
} else {
return [object autorelease];
}
}
id objc_retainAutoreleasedReturnValue(id object) {
if (get_flag(object)) {
clear_flag(object);
return object;
} else {
return [object retain];
}
}
以上2个方法摘自《Effective Objective-C 2.0》p126。笔者也尚未搞明为何objc_retainAutoreleasedReturnValue函数的else分支上要执行一次retain。希望可以交流一下。
网友评论