iOS中runtime如何實現weak變數的自動置nil和SideTable是什麼?
這是我參與11月更文挑戰的第9天,活動詳情檢視:2021最後一次更文挑戰。
runtime
對註冊的類進行佈局,對於weak
修飾的物件會放入一個hash
表中。用weak
指向的物件記憶體地址作為key,當此物件的引用計數為0的時候會dealloc
,假如weak指向的物件記憶體地址是a,那麼就會以a為鍵,在這個weak表中搜索,找到所有以a為鍵的weak物件,從而設定為nil。
說的更詳細一點的話:\
1.初始化時:runtime會呼叫objc_initWeak
函式,初始化一個新的weak指標指向物件的地址。\
2.新增引用時:objc_initWeak
函式會呼叫objc_storeWeak()
函式,objc_storeWeak()
的作用是更新指標指向,建立對應的弱引用表。\
3.釋放時,呼叫clearDeallocating
函式。clearDeallocating
函式首先根據物件地址獲取所有weak指標地址的陣列,然後遍歷這個陣列把其中的資料設為nil,最後把這個entry
從weak表中刪除,最後清理物件的記錄。
SideTable
SideTable結構體是負責管理類的引用計數表和weak表。\ 詳解:參考自《Objective-C高階程式設計》一書。\ 1.初始化時:runtime會呼叫objc_initWeak函式,初始化一個新的weak指標指向物件的地址。
{
NSObject *obj = [[NSobject alloc] init];
id __weak obj1 = obj;
}
當我們初始化一個weak變數時,runtime會呼叫NSObject.mm
中的objc_initWeak
函式。
// 編譯器的模擬程式碼
id obj1;
objc_initWeak(&obj1, obj);
/*obj引用計數為0,變數作用域結束*/
objc_destoryWeak(&obj1);
通過objc_initWeak
函式初始化“附有weak修飾符的變數(obj1)”,在變數作用域結束時通過objc_destoryWeak
函式釋放該變數(obj1)。
2.新增引用時:objc_initWeak
函式會呼叫objc_storeWeak()
函式,objc_storeWeak()
的作用是更新指標指向,建立對應的弱引用表。
objc_initWeak
函式將“附有weak修飾符的變數(obj1)”初始化為0(nil)後,會將“賦值物件”(obj)作為引數,呼叫objc_storeWeak
函式。
obj1 = 0;
obj_storeWeak(&obj1, obj);
也就是說:\
weak修飾的指標預設值是nil(在Objective-C中向nil傳送訊息是安全的)\
然後obj_storeWeak函式將0(nil)作為引數,呼叫objc_storeWeak函式。
objc_storeWeak(&obj1, 0);
前面的原始碼與下列原始碼相同。
//編譯器的模擬程式碼
id obj1;
obj1 = 0;
objc_storeWeak(&obj1, obj);
/*... obj的引用計數變為0,被置nil...*/
objc_storeWeak(&obj1, 0);
objc_storeWeak
函式把第二個引數的賦值物件(obj)的記憶體地址作為鍵值,將第一個引數__weak修飾的屬性變數(obj1)的記憶體地址註冊到weak表中。如果第二個引數(obj)為0(nil),那麼把變數(obj1)的地址從weak表中刪除。\
由於一個物件可同時複製給多個附有__weak
修飾符的變數中,所以對於一個鍵值,可註冊多個變數的地址。\
可以把objc_storeWeak(&a, b)
理解為:objc_storeWeak(value, key)
,並且當key變nil,將value置nil。在b非nil時,a和b指向同一個記憶體地址,在b變nil時,a變nil。此時向a傳送訊息不回崩潰:在Objective-C中向nil傳送訊息是安全的。
3.釋放時,呼叫clearDeallocating
函式。clearDeallocating
函式首先根據物件地址獲取所有weak指標地址的陣列,然後遍歷這個陣列把其中的資料設為nil,最後把這個entry從weak表中刪除,最後清理物件的記錄。
當weak引用指向的物件被釋放時,又是如何去處理weak指標的呢?當釋放物件時,其基本流程如下:\
1.呼叫objc_release
\
2.因為物件的引用計數為0,所以執行dealloc
\
3.在dealloc
中,呼叫了_objc-rootDealloc
函式\
4.在_objc_rootDealloc
中,呼叫了object_dispose
函式\
5.呼叫objc_destructinstance
\
6.最後呼叫objc_clear_deallocating
物件被釋放時呼叫的objc_clear_deallocating
函式:\
1.從weak表中獲取廢棄物件的地址為鍵值的記錄\
2.將包含在記錄中的所有附有weak修飾符變數的地址,賦值為nil\
3.將weak表中該記錄刪除\
4.從引用計數表中刪除廢棄物件的地址為鍵值的記錄
總結\ 其實Weak表是一個hash(雜湊)表,Key是weak所指物件的地址,Value是weak指標的地址(這個地址的值是所指物件指標的地址)陣列
- iOS之資料結構與演算法面試題2
- iOS之字串拷貝
- iOS之動態庫與靜態庫的實戰配置
- iOS之Dispatch Semaphore與NSThread runloop實現常駐執行緒
- iOS之xcconfig編寫指南
- iOS之OC與JS的互動(iOS與H5混編)
- iOS之認識Shell2-常用的命令參考1
- iOS之認識Shell-1
- iOS開發中Mach-O的體積優化2
- iOS開發中Mach-O的體積優化
- iOS中runtime如何實現weak變數的自動置nil和SideTable是什麼?
- iOS中的迴圈引用
- iOS之網路相關4:TCP和UDP
- iOS之網路相關3:HTTPS
- iOS之網路相關2:HTTP的通訊過程
- iOS之網路相關1:HTTP協議
- iOS逆向探究3:狀態暫存器
- iOS逆向探究2:彙編初探2
- iOS逆向探究1:彙編初探1
- iOS小知識之底層問題探索