iOS Runtime面試題(weak變量)

runtime如何實現weak變量的自動置nil?知道SideTable嗎?

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結構體是負責管理類的引用計數表和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_destroyWeak(&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_destroyWeak函數將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進階學習交流羣:551346706 !結實人脈、討論技術你想要的這裏都有!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章