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修饰符
__strong是id类型和对象类型默认的修饰符。
{
__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_autoreleaseReturnValue
。objc_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,直接传递。
- __weak修饰符
__weak修饰的变量不会持有对象的引用计数,当对象释放是,会将爱那个边来那个置nil。
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()会将对象注册到自动释放池里。
网友评论