OC運行時
- 動態類型
- 動態綁定
- 動態裝載
OC的消息轉發機制
分為兩步
- 實例變量會先查找自身有沒有該方法,沒有就再去父類,直到最上級父類也沒有,就會轉向第二步
- 這一步會有很多個地方讓用戶重啟消息發送過程
- resolveInstanceMethod
- forwardingTargetForSelector
- methodSignatureForSelector -> forwardInvocation
- doesNotRecognizeSelector
派發方式
- 直接派發(Direct Dispatch)
- 最快,需要調用的指令集會更少,編譯器還能夠優化,也成為靜態調用,但是缺乏動態性所有沒辦法支持繼承和多態
- 函數表派發(Table Dispatch)
- 使用一個數組存儲類聲明的每一個函數的指針,也成為virtual table(虛函數表),Swift里成為witness table.
- 每個類都會維護一個函數表,記錄類所有的函數,如果父類函數被override,則只會保存被override之后的函數,一個子類新添加的函數,都會被插入到數組的最后
- 比直接派發慢,不好擴展
- 消息機制派發(Message Dispatch)
- 調用函數最動態的方式,Cocoa的基石,支持函數替換、kvo這些功能
Swift運行時
- 純Swift類的函數不再是運行時發消息,而是類似 C++ 的 vtable,在編譯時就確定了調用哪個函數,所以沒法通過 runtime 獲取方法、屬性
- 為了兼容OC,凡是繼承自NSObject的類都會保留其動態性,能通過 runtime 拿到它的方法。新版本必須手動加上@objc
- 不管是純 Swift 類還是繼承自 NSObject 的類只要在屬性和方法前面加上 @objc 關鍵字就可以使用 runtime
下面是一些 Swift 運行時的派發方式
原始定義 | 擴展 | |
---|---|---|
值類型 | 直接派發 | 直接派發 |
協議 | 函數表派發 | 直接派發 |
類 | 函數表派發 | 直接派發 |
繼承自NSObject的類 | 函數表派發 | 消息機制派發 |
final | 直接派發 |
dynamic | 消息機制派發 |
@objc & @nonobic | 改變在OC里的可見性 |
@inline | 告訴編譯器可以直接派發 |