ARC實(shí)現(xiàn)
?
? ? ARC 由 clang (LLVM 編譯器) 3.0 以上和 objc4 Objective-C 運(yùn)行時(shí)庫(kù) 493.9 以上實(shí)現(xiàn)
?
__strong 修飾符
? ? 2 次調(diào)用 objc_msgSend 方法(alloc 和 init),變量作用域結(jié)束時(shí)通過(guò)objc_release 釋放對(duì)象,編譯器自動(dòng)插入 release
? ? 用除 alloc/new/copy/mutableCopy 外方法時(shí),release 之前調(diào)用了objc_retainAutoreleasedReturnValue 函數(shù),與之相對(duì)的是objc_autoreleaseReturnValue 函數(shù),用于 alloc/new/copy/mutableCopy 外等返回對(duì)象的實(shí)現(xiàn),返回注冊(cè)到 autoreleasepool 中的對(duì)象,但會(huì)檢查使用該函數(shù)的方法或調(diào)用方的執(zhí)行命令列表,如果之后緊接著調(diào)用objc_retainAutoreleasedReturnValue 函數(shù),那么就不將對(duì)象注冊(cè)到autoreleasepool,而是直接傳遞,即便不注冊(cè)到 autoreleasepool,也可以準(zhǔn)確獲取對(duì)象,這一過(guò)程達(dá)到了最優(yōu)化
?
__weak 修飾符
{
id __weak obj1 = obj;
}
/* 編譯器的模擬代碼 */
id obj1;
obj1 = 0;
objc_storeWeak(&obj1, obj);
objc_storeWeak(&obj1, 0);
? ? objc_storeWeak 函數(shù)把第二個(gè)參數(shù)的賦值對(duì)象的地址作為鍵值,將第一參數(shù)的附有 __weak 修飾符的變量的地址注冊(cè)到 weak 表。如果第二參數(shù)為 0,則把變量從weak 表刪除
? ? weak 表與引用計(jì)數(shù)表相同,作為散列表實(shí)現(xiàn)。將廢棄對(duì)象的地址作為鍵值進(jìn)行檢索,就能高效獲取對(duì)應(yīng)的 __ weak 變量的地址。由于一個(gè)對(duì)象可賦值給多個(gè)__weak 變量,所以對(duì)一個(gè)鍵值,可注冊(cè)多個(gè)變量地址
? ? 釋放對(duì)象時(shí),最后調(diào)用的 objc_clear_deallocating 函數(shù)動(dòng)作如下:
- 從 weak 表獲取廢棄對(duì)象的地址作為鍵值的記錄
- 將包含在記錄中的所有附有 __weak 修飾符變量的地址,賦值為 nil
- 從 weak 表刪除該記錄
- 從引用計(jì)數(shù)表中刪除廢棄對(duì)象的地址為鍵值的記錄
? ? 可見,如果大量使用 __weak,會(huì)消耗相應(yīng)的 CPU,所以只在需要避免循環(huán)引用時(shí)使用
id __weak obj = [[NSObject alloc] init];
id __unsafe_unretained obj = [[NSObject alloc] init];
//編譯器警告
[[NSObject alloc] init];
//ARC 無(wú)效時(shí)會(huì)發(fā)生內(nèi)存泄漏
(void)[[NSObject alloc] init];
//避免警告
//ARC 有效時(shí),編譯器生成并立即調(diào)用 objc_release 函數(shù),不會(huì)造成內(nèi)存泄漏
//可以調(diào)用被立即釋放的對(duì)象的實(shí)例方法,調(diào)用完就被釋放
? ? 訪問(wèn)附有 __weak 修飾符的變量時(shí),調(diào)用了 objc_loadWeakRetained 函數(shù)和objc_autorelease 函數(shù)
- objc_loadWeakRetained 函數(shù)取出附有 __weak 變量所引用的對(duì)象并 retain
- objc_autorelease 函數(shù)將對(duì)象注冊(cè)到 autoreleasepool 中
? ? 在大量使用 __ weak 變量時(shí),注冊(cè)到 autoreleasepool 中對(duì)象也大量增加,最好先暫時(shí)賦值給附有 __strong 變量再使用
獨(dú)自實(shí)現(xiàn)引用計(jì)數(shù)的類大多不支持 __weak,當(dāng) allowsWeakReference/retainWeakReference 方法返回 NO 時(shí),也不能使用,該變量將變?yōu)?nil
?
__autoreleasing 修飾符
沒(méi)啥說(shuō)的,就調(diào)用 objc_autorelease 函數(shù)
?
引用計(jì)數(shù)
用 _objc_rootRetainCount 函數(shù)獲取引用計(jì)數(shù)值(不完全可信
強(qiáng)引用持有 +1,弱引用不變,向 autoreleasepool 注冊(cè)+1,訪問(wèn) __weak +1