美文网首页内存管理
objc_autoreleaseReturnValue和objc

objc_autoreleaseReturnValue和objc

作者: KardelShaw | 来源:发表于2016-12-13 21:41 被阅读1201次

    注:本文在每段代码中首段标有 "//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。希望可以交流一下。

    相关文章

      网友评论

        本文标题:objc_autoreleaseReturnValue和objc

        本文链接:https://www.haomeiwen.com/subject/ngpbmttx.html