+load和+initialize方法調用時機

一、+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方法)