runtime 就是系統在運行時的一些機制,其中最主要的是消息機制。
OC代碼,最終都是轉成了runtime(c語言庫)的C語言實現。
eg:類轉成了runtime庫裏面的結構體等數據類型
方法轉成了runtime庫裏面的C語言函數,平時調方法都是轉成了objc_msgSend函數(因此說OC有個消息發送機制)
函數
[Entity alloc] init] objc_msgSend("Entity", "alloc") objc_msgSend("Entity", "init") objc_msgSend(objc_msgSend("Entity", "alloc"), "init")
runtime的多態:
對於C語言,編譯完成以後函數的調用關係就已經肯定。
OC的函數調用成爲消息發送。屬於動態調用過程。(在編譯階段,OC能夠調用任何函數,即便這個函數並未實現,只要申明過就不會報錯。)。只有在真正運行的時候纔會根據函數的名稱找 到對應的函數來調用。
指針
[obj makeText]; objc_msgSend(obj,@selector(makeText));
首先咱們來看看obj這個對象,iOS中的obj都繼承於NSObject。
code
@interface NSObject <nsobject> { Class isa OBJC_ISA_AVAILABILITY; }</nsobject> 在NSObjcet中存在一個Class的isa指針。而後咱們看看Class: typedef struct objc_class *Class; struct objc_class { Class isa; // 指向metaclass Class super_class ; // 指向其父類 const char *name ; // 類名 long version ; // 類的版本信息,初始化默認爲0,能夠經過runtime函數class_setVersion和class_getVersion進行修改、讀取 long info; // 一些標識信息,如CLS_CLASS (0x1L) 表示該類爲普通 class ,其中包含對象方法和成員變量;CLS_META (0x2L) 表示該類爲 metaclass,其中包含類方法; long instance_size ; // 該類的實例變量大小(包括從父類繼承下來的實例變量); struct objc_ivar_list *ivars; // 用於存儲每一個成員變量的地址 struct objc_method_list **methodLists ; // 與 info 的一些標誌位有關,如CLS_CLASS (0x1L),則存儲對象方法,如CLS_META (0x2L),則存儲類方法; struct objc_cache *cache; // 指向最近使用的方法的指針,用於提高效率; struct objc_protocol_list *protocols; // 存儲該類遵照的協議 }
注意:全部metaclass中isa指針都指向跟metaclass。而跟metaclass則指向自身。Root metaclass是經過繼承Root class產生的。與root class結構體成員一致,也就是前面提到的結構。不一樣的是Root metaclass的isa指針指向自身。對象
Class類中其餘的成員這裏就先不作過多解釋了,下面咱們來看看:繼承
@selector (makeText):這是一個SEL方法選擇器。SEL其主要做用是快速的經過方法名字(makeText)查找到對應方法的函數指針,而後調用其函 數。SEL其自己是一個Int類型的一個地址,地址中存放着方法的名字。對於一個類中。每個方法對應着一個SEL。因此iOS類中不能存在2個名稱相同 的方法,即便參數類型不一樣,由於SEL是根據方法名字生成的,相同的方法名稱只能對應一個SEL。get
下面咱們就來看看具體消息發送以後是怎麼來動態查找對應的方法的。編譯器
首先,編譯器將代碼[obj makeText];轉化爲objc_msgSend(obj, @selector (makeText));,在objc_msgSend函數中。首先經過obj的isa指針找到obj對應的class。在Class中先去cache中 經過SEL查找對應函數method(猜想cache中method列表是以SEL爲key經過hash表來存儲的,這樣能提升函數查找速度),若 cache中未找到。再去methodList中查找,若methodlist中未找到,則取superClass中查找。若能找到,則將method加 入到cache中,以方便下次查找,並經過method中的函數指針跳轉到對應的函數中去執行。hash