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];
}
編譯成中間語言后:
上面劃線的模擬代碼大概是這樣的:
{
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()會將對象注冊到自動釋放池里。