+load和+initialize方法呼叫時機

俊華的部落格發表於2021-01-20

一、+load方法什麼時候呼叫

+load方法會在runtime載入類、分類時呼叫(程式執行起來會先去載入呼叫+load 跟你引用沒有引用其標頭檔案沒有關係)。
每個類、分類的+load,在程式執行過程中只呼叫一次

呼叫順序:

  1. 先呼叫類的+load

    • 按照編譯先後順序呼叫(先編譯,先呼叫)
    • 呼叫子類的+load之前會先呼叫父類的+load
  2. 再呼叫分類的+load

    • 按照編譯先後順序呼叫(先編譯,先呼叫)

 

 

 

二、為什麼原本類的+load方法不會被分類的+load方法覆蓋呢?

這是由於+load方法是根據方法地址直接呼叫,並不是經過objc_msgSend函式呼叫

+load方法相關原始碼閱讀順序:

  1. _objc_init
  2. load_images
  3. prepare_load_methods
    • schedule_class_load
    • add_class_to_loadable_list
    • add_category_to_loadable_list
  4. calls
    • call_class_loads
    • call_category_loads
    • (*load_method)(cls, SEL_load)

 

三、+initialize方法呼叫的時機

+initialize方法會在類第一次接收到訊息時呼叫。

呼叫順序:先呼叫父類的+initialize,再呼叫子類的+initialize,每個類只會初始化1次

+initialize方法相關原始碼閱讀順序:

  1. objc-msg-arm64.s

    • objc_msgSend
  2. objc-runtime-new.mm

    • class_getInstanceMethod
    • lookUpImpOrNil
    • lookUpImpOrForward
    • _class_initialize
    • callInitialize
    • objc_msgSend(cls, SEL_initialize)

+initialize和+load的最大區別是,+initialize是通過objc_msgSend進行呼叫的,所以有以下特點:

  • 如果子類沒有實現+initialize,會呼叫父類的+initialize(所以父類的+initialize可能會被呼叫多次)
  • 如果分類實現了+initialize,就覆蓋類本身的+initialize呼叫

 

四、總結

load、initialize方法的區別什麼?
1.呼叫方式
1> load是根據函式地址直接呼叫
2> initialize是通過objc_msgSend呼叫

2.呼叫時刻
1> load是runtime載入類、分類的時候呼叫(只會呼叫1次)
2> initialize是類第一次接收到訊息的時候呼叫,每一個類只會initialize一次(父類的initialize方法可能會被呼叫多次)

load、initialize的呼叫順序?
1.load
1> 先呼叫類的load
a) 先編譯的類,優先呼叫load
b) 呼叫子類的load之前,會先呼叫父類的load

2> 再呼叫分類的load
a) 先編譯的分類,優先呼叫load

2.initialize
1> 先初始化父類
2> 再初始化子類(可能最終呼叫的是父類的initialize方法)

 

相關文章