iOS小知識之底層問題探索

語言: CN / TW / HK

小知識,大挑戰!本文正在參與“程式設計師必備小知識”創作活動。

1.主類方法和分類方法的呼叫順序?

1.1 普通方法

普通方法,包括initialize,優先分類中的方法呼叫\ 因為分類的方法是在類realize之後attach進去的,所以插在前面

1.2 load方法

load方法,優先主類,然後分類\ 因為類的初始化,優先主類,讀取ro。然後分類初始化,讀取rwe

1.3 多分類

多個分類之間,看檔案的編譯順序。load方法,先編譯的分類先執行。同名方法,最後編譯的分類中的方法會執行

2. load、initialize、cxx的呼叫順序?

load方法和cxx函式,在程式啟動時自動呼叫,呼叫順序:load -> cxx -> main\ 對於相同映象檔案,load方法一定在cxx函式之前\ 不同映象檔案的呼叫順序:系統庫優先 -> 動態庫 -> 主程式 initialize方法,屬於懶載入方法,在物件首次訊息傳送時呼叫\ objc中的cxx函式,它會在_objc_init函式中,呼叫static_init函式,執行C++靜態建構函式

image-10.png

3. 能否在執行時對編譯後的類新增例項變數?

不能,因為編譯後的例項變數儲存在ro中,一旦編譯完成,記憶體結構就完全確定了,無法修改。可以對編譯後的類新增屬性和方法。

4.能否對執行時建立的類新增例項變數?

可以對執行時建立的類新增例項變數,使用objc_allocateClassPair建立類,只要在objc_registerClassPair註冊之前,可新增例項變數。一旦註冊後,無法新增例項變數。\ 使用class_addIvar新增例項變數,新增錢進行flags & RW_CONSTRUCTING的條件判斷

``` BOOL class_addIvar(Class cls, const char name, size_t size, uint8_t alignment, const char type) { ...

// No class variables 
if (cls->isMetaClass()) {
    return NO; 
}

// Can only add ivars to in-construction classes. 
if (!(cls->data()->flags & RW_CONSTRUCTING)) { 
    return NO; 
}

...

} `` 呼叫objc_registerClassPair函式,會對flags`進行標記

``` void objc_registerClassPair(Class cls) { ...

// Clear "under construction" bit, set "done constructing" bit 
cls->ISA()->changeInfo(RW_CONSTRUCTED, RW_CONSTRUCTING | RW_REALIZING); 
cls->changeInfo(RW_CONSTRUCTED, RW_CONSTRUCTING | RW_REALIZING);

...

} ```

5.Runtime是如何實現weak的,為什麼可以自動置nil?

  • 1.通過SideTable找到我們的weak_table
  • 2.weak_table根據referent找到或者建立weak_entry_t
  • 3.然後append_referrer(entry, referrer)將我的新弱引用的物件加進去entry
  • 4.最後weak_entry_insertentry加入到我們的weak_table

image-11.png