1. 程式人生 > >iOS weak底層實現原理

iOS weak底層實現原理

今年年底做了很多決定,離開工作三年的深圳,來到了上海,發現深圳和上海在蘋果這方面還是差距有點大的,上海的市場8成使用swift程式設計,而深圳8成的使用OC,這點還是比較讓準備來上海打拼的蘋果工程師有點小壓力的。畢竟以後蘋果還是swift使用的多,現在已經swift4.x了,所以早點接觸,還是有優勢的,不過。咱們閒話少說,今天我們將繼續講述OC修飾屬性的一個Weak修飾符的底層實現,有時間我會花時間講述swift4.x。

 

一、weak基本用法

weak是弱引用,用weak來修飾、描述所引用物件的計數器並不會加1,而且weak會在引用物件被釋放的時候自動置為nil,這也就避免了野指標訪問壞記憶體而引起奔潰的情況,另外weak也可以解決迴圈引用。

拓展:為什麼修飾代理使用weak而不是用assign?

assign可用來修飾基本資料型別,也可修飾OC的物件,但如果用assign修飾物件型別指向的是一個強指標,當指向的這個指標釋放之後,它仍指向這塊記憶體,必須要手動給置為nil,否則會產生野指標,如果還通過此指標操作那塊記憶體,會導致EXC_BAD_ACCESS錯誤,呼叫了已經被釋放的記憶體空間;而weak只能用來修飾OC物件,而且相比assign比較安全,如果指向的物件消失了,那麼它會自動置為nil,不會導致野指標。

 

二、weak原理概括

weak表其實是一個雜湊表,key是所指物件的指標,value是weak指標的地址陣列。(value是陣列的原因是:因為一個物件可能被多個弱引用指標指向)

Runtime維護了一張weak表,用來儲存某個物件的所有的weak指標。

 

weak原理實現過程三步驟

  1. 初始化開始時,會呼叫objc_initWeak函式,初始化新的weak指標指向物件的地址

  2.緊接著,objc_initWeak函式裡面會呼叫objc_storeWeak() 函式,objc_storeWeak() 函式的作用是用來更新指標的指向,建立弱引用表。

   3.在最後會呼叫clearDeallocating函式。而clearDeallocating函式首先根據物件的地址獲取weak指標地址的陣列,然後緊接著遍歷這個陣列,將其中的陣列開始置為nil,把這個entry從weak表中刪除,最後一步清理物件的記錄。

 

拓展:詳細步驟

  1. 初始化開始時,會呼叫objc_initWeak函式,初始化新的weak指標指向物件的地址

當我們初始化weak變數時,runtime會呼叫NSObject.mm中的objc_initWeak,而objc_initWeak函式裡面的實現如下:

id objc_initWeak(id *location, id newObj) {
// 檢視物件例項是否有效,無效物件直接導致指標釋放
    if (!newObj) {
        *location = nil;
        return nil;
    }
    // 這裡傳遞了三個 bool 數值
    // 使用 template 進行常量引數傳遞是為了優化效能
    return storeWeakfalse/*old*/, true/*new*/, true/*crash*/>
    (location, (objc_object*)newObj);
}

通過上面程式碼可以看出,objc_initWeak()函式首先判斷指標指向的類物件是否有效,無效,直接返回;否則通過storeWeak()被註冊為一個指向value的_weak物件

  2. objc_initWeak函式裡面會呼叫objc_storeWeak() 函式,objc_storeWeak() 函式的作用是用來更新指標的指向,建立弱引用表。

  3..在最後會呼叫clearDeallocating函式。而clearDeallocating函式首先根據物件的地址獲取weak指標地址的陣列,然後緊接著遍歷這個陣列,將其中的陣列開始置為nil,把這個entry從weak表中刪除,最後一步清理物件的記錄。

 

問:當weak指向的物件被釋放時,如何讓weak指標置為nil的呢?

1、呼叫objc_release
2、因為物件的引用計數為0,所以執行dealloc
3、在dealloc中,呼叫了_objc_rootDealloc函式
4、在_objc_rootDealloc中,呼叫了object_dispose函式
5、呼叫objc_destructInstance
6、最後呼叫objc_clear_deallocating,詳細過程如下:
   a. 從weak表中獲取廢棄物件的地址為鍵值的記錄
   b. 將包含在記錄中的所有附有 weak修飾符變數的地址,賦值為   nil
   c. 將weak表中該記錄刪除
   d. 從引用計數表中刪除廢棄物件的地址為鍵值的記錄

 

本文講述了weak底層實現原理,也是面試經常被問到的一點,希望對大家有所幫助,謝謝!