iOS OC方法調用過程(消息轉發objc_msgSend()補充)

runtime賦予OC的動態特性

Object-C因為有了強大的runtime而成為一門動態語言,其動態性體現在:動態綁定,動態加載,動態類型。

  1. 動態綁定:靜態語言的函數調用是在編譯過程中就已經明確指定了。而動態語言,編譯過程沒有確定方法的調用順序,是在運行時通過“消息機制”動態決定的。這個時候就牽扯到動態綁定了。OC語言中,只需記住關鍵詞(@selector/SEL)即可。通過SEL變量綁定一個方法,SEL存儲的是方法的內存地址,調用方法的時候直接查詢這個地址。
  2. 動態類型:簡單說就是id類型。編譯的時候不去識別,在運行時才決定是什么類型。
  3. 動態加載:簡單理解就是,在程序運行時,根據設備屏幕不同,動態去選擇加載2X還是3X圖片資源。動態加載應該不僅僅指動態加載圖片資源,具體還需調研。
    而這些動態特性,都是基于runtime的貢獻。

一,調用原理


image.png

方法的調用,首先根據isa 指針 找到類結構體,類結構體中有緩存列表 方法列表,變量列表等等(自己可以去查看一下)

方法會先在緩存列表查找這個方法是否存在,在去方法列表查找,之后去父類中緩存列表和方法列表查找,之后到根元類中查找,還沒有找到就會進行第二步消息轉發
1.給實例對象消息的過程(調用對象方法)

根據對象的isA指針去該對象的類方法中查找,如果找到了就執行
如果沒有找到,就去該類的父類類對象中查找
如果沒有找到就一直往上找,直到根類(NSObject)
如果都沒有找到就報錯(還有三次挽救的機會)

2.給類對象發送消息(調用類方法)

根據類對象的isA指針去元對象中查找,如果找到了就執行
如果沒有找到就去父元對象中查找
如果如果沒有找到就一直往上查找,直到根類(NSOject)
如果都沒有找到就報錯(還有三次挽救的機會)
首先去該類的cache中查詢,如果找到了,就直接返回;
如果沒找到,就去methodList中查找。如果找到了,則將方法的IMP(方法實現的指針)返回,并將IMP存入Cache;
如果還沒找到,就通過super_class找到父類,在父類的methodList中查找;   
如果在所有的父類中都沒找到這個方法,就會去進行動態決議和消息轉發;
[圖片上傳中...(image.png-54385c-1616659124477-0)]
如果動態決議和消息轉發返回NO和nil,就會拋出異常。
[圖片上傳中...(image.png-81e9e0-1616659170257-0)]

消息發送階段:從緩存中查找方法,如果找到即調用,沒找到則進入動態解析階段
動態解析階段:負責動態添加方法實現,如果沒有實現,則進入消息轉發階段
消息轉發階段:將消息轉發給可以處理消息的對象

消息發送(第一步)

image.png

動態解析(第二步)

當本類包括父類cache包括class_rw_t中都找不到方法時,就會進入動態方法解析階段;
動態解析對象方法時,會調用+(BOOL)resolveInstanceMethod:(SEL)sel方法。
動態解析類方法時,會調用+(BOOL)resolveClassMethod:(SEL)sel方法。


image.png
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容