ARC原理分析

2020-04-27  本文已影响0人  zziazm

https://clang.llvm.org/docs/AutomaticReferenceCounting.html#arc-runtime-objc-retainautorelease

编译器会自动添加retain、release和autorelease,还有运行时的协助。

可以通过以下方式将代码编译成中间语言:
clang -S -fobjc-arc -emit-llvm main.m -o main.ll
可以看到编译器是在什么地方做的操作。

{    
   __strong  id obj = [[NSObject alloc] init];
}

编译成中间语言后:


WeChat601fb47f7f90116f31cf7e35fe4ea621.png

上面划线的模拟代码大概是这样的:

{
 id obj = objc_msgSend(NSObject, @selector(alloc));
 objc_msgSend(obj, @selector(init));
 objc_storeStrong(&obj, null);
}

了解一下objc_storeStrong代码:

void objc_storeStrong(id *object, id value) {
  id oldValue = *object;
  value = [value retain];
  *object = value;
  [oldValue release];
}

第一个参数是object的地址,这个函数相当于对对象object做了一次release操作。
因此,__strong修饰的alloc出来的对象在出作用域时编译器会添加 release。

再看一下下面的代码:

{
    __strong  id obj1 = [[NSObject alloc] init];
    __strong  id obj2 = obj1;
}

编译器模拟代码:

{
 id obj1 = objc_msgSend(NSObject, @selector(alloc));
 objc_msgSend(obj1, @selector(init));
 id obj2 = objc_retain(obj1);
 objc_storeStrong(&obj1, null);
 objc_storeStrong(&obj2, null);
}

可以看到,__strong修饰的对象直接赋值时编译器会添加retain。

再看一下使用类方法构造的对象:

 __strong NSArray *arr = [NSArray array];

编译器模拟代码:

 id arr = objc_msgSend(NSArray, @selector(array));
objc_retainAutoreleasedReturnValue(arr);
objc_storeStrong(&arr, null);

使用类方法构造的对象和alloc init不同的地方在于多了一个objc_retainAutoreleasedReturnValue(arr).
objc_retainAutoreleasedReturnValue这个函数是成对出现的,和它对应的是objc_autoreleaseReturnValueobjc_autoreleaseReturnValue是在类方法里出现的:

+ (NSArray *)array{
    return [[NSArray alloc] init];
}

编译器模拟代码:

 id obj = objc_msgSend(NSObject, @selector(alloc));
objc_msgSend(obj, @selector(init));
return objc_autoreleaseReturnValue(obj);

objc_retainAutoreleasedReturnValue()
objc_autoreleaseReturnValue ()这两个函数的作用是什么呢?
objc_autorelease()函数会将对象注册到autorelesaepool中,objc_autoreleaseReturnValue和它不同,objc_autoreleaseReturnValue会检查使用该函数的方法或调用放的执行命令列表,如果方法或函数调用方紧接着调用了objc_retainAutoreleasedReturnValue,就不会把返回值注册到autorelesaepool中,这样就做了一个优化,可以不将对象注册到autorelesaepool,直接传递。

NSObject *obj;
__weak id obj1 = obj;

编译器模拟代码里会有四个函数:

@objc_initWeak()
@objc_loadWeakRetained()
@objc_release()
@objc_destroyWeak() 

objc_loadWeakRetained()函数会retain对象,这样可以保证在使用weak对象时对象不会被释放掉。
-__autoreleasing
__autoreleasing修饰的变量会注册到自动释放池里:

__autoreleasing NSObject *obj = [NSArray array];

编译器模拟代码:

 id obj = objc_msgSend(NSObject, @selector(alloc));
objc_autorelease(obj);

objc_autorelease()会将对象注册到自动释放池里。

上一篇下一篇

猜你喜欢

热点阅读