objc_msgSend函數
關於Selector,什么 是Selector,Selector就是一個字符串,用來表示一個方法。
在Objective-C中,消息是直到運行的時候才和方法實現綁定的。編譯器會把一個消息表達式,
[receiver message] |
轉換成一個對消息函數objc_msgSend的調用。該函數有兩個主要參數:消息接收者和消息對應的方法名字——也就是方法選標:
objc_msgSend(receiver, selector) |
objc_msgSend(receiver, selector, arg1, arg2, ...) |
該消息函數做了動態綁定所需要的一切:
-
然后將消息接收者對象(指向消息接收者對象的指針)以及方法中指定的參數傳給找到的方法實現。
-
最后,將方法實現的返回值作為該函數的返回值返回。
消息機制的關鍵在於編譯器為類和對象生成的結構。每個類的結構中至少包括兩個基本元素:
-
指向父類的指針。
-
類的方法表。方法表將方法選標和該類的方法實現的地址關聯起來。例如,
setOrigin::的方法選標和setOrigin::的方法實現的地址關聯,display的方法選標和display的方法實現的地址關聯,等等。
當新的對象被創建時,其內存同時被分配,實例變量也同時被初始化。對象的第一個實例變量是一個指向該對象的類結構的指針,叫做isa。通過該指針,對象可以訪問它對應的類以及相應的父類。
注意:盡管嚴格來說這並不是Obective-C語言的一部分,但是在Objective-C運行時系統中對象需要有isa指針。對象和結構體struct objc_object(在objc/objc.h中定義)必須“一致”。然而,您很少需要創建您自己的根對象,因為從NSObject或者NSProxy繼承的對象都自動包括isa變量。
類和對象的結構如圖 3-1所示。
當對象收到消息時,消息函數首先根據該對象的isa指針找到該對象所對應的類的方法表,並從表中尋找該消息對應的方法選標。如果找不到,objc_msgSend將繼續從父類中尋找,直到NSObject類。一旦找到了方法選標, objc_msgSend則以消息接收者對象為參數調用,調用該選標對應的方法實現。
這就是在運行時系統中選擇方法實現的方式。在面向對象編程中,一般稱作方法和消息動態綁定的過程。
為了加快消息的處理過程,運行時系統通常會將使用過的方法選標和方法實現的地址放入緩存中。每個類都有一個獨立的緩存,同時包括繼承的方法和在該類中定義的方法。消息函數會首先檢查消息接收者對象對應的類的緩存(理論上,如果一個方法被使用過一次,那么它很可能被再次使用)。如果在緩存中已經有了需要的方法選標,則消息僅僅比函數調用慢一點點。如果程序運行了足夠長的時間,幾乎每個消息都能在緩存中找到方法實現。程序運行時,緩存也將隨着新的消息的增加而增加。
