擴展:編譯時
看到運行時就會想到編譯時,編譯時主要是將源代碼翻譯成可識別的機器語言,如果編譯時類型檢查等翻譯過程中發現語法分析之類有錯誤會給出相應的提示。比如OC,swift,Java等高級語言的可讀性比較強,但是一般不會被機器直接識別,所以需要將他們編譯成機器語言(彙編等),轉爲二進制
Runtime簡介
在 Objective-C 中,消息是直到運行的時候才和方法實現綁定的。編譯器會把一個消息表達式,
[receiver message]
轉換成一個對消息函數objc_msgSend的調用。該函數有兩個主要參數:消息接收者和消息對應的方法——也就是方法編號(name),發送消息時候,通過sel找到函數實現的指針imp
objc_msgSend(receiver, selector)
編譯器將自動插入調用該消息函數的代碼,同時接收消息中的任意數目的參數:
objc_msgSend(receiver, selector, arg1, arg2, ...)
該消息函數做了動態綁定所需要的一切:
- 它首先找到選標所對應的方法實現。因爲不同的類對同一方法可能會有不同的實現,所以找到的方法實現依賴於消息接收者的類型。
- 然後將消息接收者對象(指向消息接收者對象的指針)以及方法中指定的參數傳給找到的方法實現。
- 最後,將方法實現的返回值作爲該函數的返回值返回。
消息機制的關鍵在於編譯器爲類和對象生成的結構。每個類的結構中至少包括兩個基本元素:
- 指向父類的指針。
- 類的方法表。方法表將方法選標和該類的方法實現的地址關聯起來。
和運行時系統的交互
Objective-C 程序有三種途徑和運行時系統交互:
- 通過Objective-C源代碼
大部分情況下,運行時系統在後臺自動運行,當編譯Objective-C類和方法時,編譯器爲實現語言動態特性將自動創建一些數據結構和函數。運行時系統的主要功能就是根據源代碼中的表達式發送消息。 - 通過Foundation框架中 NSObject 的方法
Cocoa程序中絕大部分類都是NSObject類的子類,所以大部分都繼承了NSObject類的方法,因而繼承 了NSObject的行爲。然而,某些情況下, NSObject類僅僅定義了完成某件事情的模板,而沒有提供所有需要的代碼(比如 description 方法)。某些 NSObject 的方法只是簡單地從運行時系統中獲得信息,從而允許對象進行一定程度的自我檢查(比如methodForSelector方法返回指定方法實現的地址)。 - 通過調用運行時系統函數
直接調用運行時系統給我們提供的API接口
Runtime函數註釋
// 1.objc_xxx系列函數 宏觀使用,如類與協議的空間分配,註冊,註銷等操作
// 函數名稱 函數作用
objc_getClass 獲取Class對象
objc_getMetaClass 獲取MetaClass對象
objc_allocateClassPair 分配空間,創建類(僅在 創建之後,註冊之前 能夠添加成員變量)
objc_registerClassPair 註冊一個類(註冊後方可使用該類創建對象)
objc_disposeClassPair 註銷某個類
objc_allocateProtocol 開闢空間創建協議
objc_registerProtocol 註冊一個協議
objc_constructInstance 構造一個實例對象(ARC下無效)
objc_destructInstance 析構一個實例對象(ARC下無效)
objc_setAssociatedObject 爲實例對象關聯對象
objc_getAssociatedObje*ct 獲取實例對象的關聯對象
objc_removeAssociatedObjects 清空實例對象的所有關聯對象
// 2.class_xxx系列函數 類的內部,如實例變量,屬性,方法,協議等相關問題
函數名稱 函數作用
class_addIvar 爲類添加實例變量
class_addProperty 爲類添加屬性
class_addMethod 爲類添加方法
class_addProtocol 爲類遵循協議
class_replaceMethod 替換類某方法的實現
class_getName 獲取類名
class_isMetaClass 判斷是否爲元類
objc_getProtocol 獲取某個協議
objc_copyProtocolList 拷貝在運行時中註冊過的協議列表
class_getSuperclass 獲取某類的父類
class_setSuperclass 設置某類的父類
class_getProperty 獲取某類的屬性
class_getInstanceVariable 獲取實例變量
class_getClassVariable 獲取類變量
class_getInstanceMethod 獲取實例方法
class_getClassMethod 獲取類方法
class_getMethodImplementation 獲取方法的實現
class_getInstanceSize 獲取類的實例的大小
class_respondsToSelector 判斷類是否實現某方法
class_conformsToProtocol 判斷類是否遵循某協議
class_createInstance 創建類的實例
class_copyIvarList 拷貝類的實例變量列表
class_copyMethodList 拷貝類的方法列表
class_copyProtocolList 拷貝類遵循的協議列表
class_copyPropertyList 拷貝類的屬性列表
// 3.object_xxx系列函數 對象的角度,如實例變量
函數名稱 函數作用
object_copy 對象copy(ARC無效)
object_dispose 對象釋放(ARC無效)
object_getClassName 獲取對象的類名
object_getClass 獲取對象的Class
object_setClass 設置對象的Class
object_getIvar 獲取對象中實例變量的值
object_setIvar 設置對象中實例變量的值
object_getInstanceVariable 獲取對象中實例變量的值 (ARC中無效,使用object_getIvar)
object_setInstanceVariable 設置對象中實例變量的值 (ARC中無效,使用object_setIvar)
// 4.method_xxx系列函數 方法內部,如方法的參數及返回值類型和方法的實現
函數名稱 函數作用
method_getName 獲取方法名
method_getImplementation 獲取方法的實現
method_getTypeEncoding 獲取方法的類型編碼
method_getNumberOfArguments 獲取方法的參數個數
method_copyReturnType 拷貝方法的返回類型
method_getReturnType 獲取方法的返回類型
method_copyArgumentType 拷貝方法的參數類型
method_getArgumentType 獲取方法的參數類型
method_getDescription 獲取方法的描述
method_setImplementation 設置方法的實現
method_exchangeImplementations 替換方法的實現
// 5.property_xxx系列函數 屬性*內部,如屬性的特性等
函數名稱 函數作用
property_getName 獲取屬性名
property_getAttributes 獲取屬性的特性列表
property_copyAttributeList 拷貝屬性的特性列表
property_copyAttributeValue 拷貝屬性中某特性的值
// 6.protocol_xxx系列函數 協議相關
函數名稱 函數作用
protocol_conformsToProtocol 判斷一個協議是否遵循另一個協議
protocol_isEqual 判斷兩個協議是否一致
protocol_getName 獲取協議名稱
protocol_copyPropertyList 拷貝協議的屬性列表
protocol_copyProtocolList 拷貝某協議所遵循的協議列表
protocol_copyMethodDescriptionList 拷貝協議的方法列表
protocol_addProtocol 爲一個協議遵循另一協議
protocol_addProperty 爲協議添加屬性
protocol_getProperty 獲取協議中的某個屬性
protocol_addMethodDescription 爲協議添加方法描述
protocol_getMethodDescription 獲取協議中某方法的描述
// 7.ivar_xxx 系列函數 實例變量相關
函數名稱 函數作用
ivar_getName 獲取Ivar名稱
ivar_getTypeEncoding 獲取類型編碼
ivar_getOffset 獲取偏移量
// 8.sel_xxx系列函數 方法編號相關
函數名稱 函數作用
sel_getName 獲取名稱
sel_getUid 註冊方法
sel_registerName 註冊方法名
sel_isEqual 判斷方法是否相等
// 9.imp_xxx系列函數 方法實現相關
函數名稱 函數作用
imp_implementationWithBlock 通過代碼塊創建IMP
imp_getBlock 獲取函數指針中的代碼塊
imp_removeBlock 移除IMP中的代碼塊
如果想繼續探究Runtime底層原理,下篇是Runtime源碼分析,包括動態方法解析和消息轉發。
該文章爲記錄本人的學習路程,希望能夠幫助大家,也歡迎大家點贊留言交流!!!文章地址https://www.jianshu.com/p/eddc9bdb46ea