概述:runtime也叫運行時,是壹套低級的C語言API,是iOS系統的核心之壹。壹個開發人員可以在編碼過程中向任何對象發送消息,但只在編譯階段決定向接收方發送消息,接收方如何響應和處理消息取決於運行時。
?在C語言中,編譯器決定調用哪個函數,而OC的函數屬於動態調用過程,編譯器並不能真正決定調用哪個函數,只有在真正運行時,才會根據函數名找到相應的函數進行調用。OC是壹種動態語言,這意味著它不僅需要壹個編譯器,還需要壹個運行時系統來動態創建類和對象,傳遞和發送消息。
1.消息轉發
運行庫的主要功能是消息傳遞。如果在對象中找不到該消息,它將被轉發。Objective-C是壹種動態語言,這意味著它不僅需要編譯器,還需要壹個運行時系統來動態創建類和對象,並傳遞和轉發消息。運行時的核心是消息傳遞。
(1)消息傳遞的過程
壹個對象的方法【obj test】,編譯器把它變成消息發送objc _ msgsend (obj,test),運行時執行的過程如下。
A.首先通過obj的isa指針找到它的類。
B.在類的方法列表中查找測試
如果在類中沒有找到test,繼續在它的超類中尋找它。
D.壹旦找到函數測試,就執行它的IMP。
因為效率問題,每條消息遍歷壹次objc_method_list是不合理的,所以需要緩存頻繁調用的函數來提高函數查詢的效率。這就是objc_class的另壹個重要成員objc_cache的作用。找到測試後,使用測試的method_name作為鍵,method_imp作為值。當您再次收到測試消息時,您可以直接在緩存中查找它。
類對象(objc_class)
Objective-C類由類類型表示,它實際上是壹個指向objc_class結構的指針。struct objc_class結構中定義了許多變量。指向父類的指針、類名、版本、實例變量列表(ivars)、方法列表(緩存)和協議列表(協議)存儲在該結構中。這樣,壹個類對象就是壹個結構struct objc_class,存儲在這個結構中的數據就是元數據。
理解運行時意味著理解iOS的數據存儲及其類、實例、類對象和元類之間的關系和功能。
(2)消息轉發機制
歸根結底,Objective-C中所有方法調用的本質都是向對象發送消息。
1.在類-(void)測試中創建方法
2.2.iOS系統為此方法創建壹個編號SEL(test ),並將其添加到方法列表中。
3.當調用該方法時,系統在方法列表中查找該方法,並在找到時執行該方法。
所以調用壹個方法會發送壹次消息,也就是會在這個類的方法列表中找到。如果在這個類中找不到,將在這個類的父類中找到。如果仍然沒有找到父類,它將被搜索到繼承樹的根。如果沒有找到或者消息轉發不成功,將報告為無法識別的選擇器錯誤。
1.動態方法分析
Objective-C運行時將調用+resolveInstanceMethod:或?+resolveClassMethod:讓您有機會提供函數實現。如果添加壹個函數並返回YES,運行時將重新啟動消息發送過程。如下圖所示:
雖然沒有foo的實現函數:,但是通過class_addMethod()動態添加fooMethod函數,函數執行打印成功。如果reslove返回NO,運行時將進入下壹步:forwardingTargetSelector。
2.直接消息轉發
如果目標對象實現forwardingTargetSelector,運行時將在此時調用此方法,讓您有機會將此消息轉發給其他對象。
從圖中可以看出,我們通過forwardingTargetForSelector方法將當前類的方法傳遞給父類,打印成功。
3.完成消息轉發
如果上壹步無法處理未知消息,唯壹能做的就是啟動消息轉發機制。首先,它發送壹條methodSignatureForSelector消息來獲取函數的參數和返回值類型。如果methodSignatureForSelector返回nil,運行時將發出doesNotRecognizeSelector。如果返回簽名函數,運行時將創建NSInvocation對象,並向目標對象發送forwardInvocation消息。
運行時的實際應用
1.使用運行時交換方法
2.動態添加法(目前還不太了解)
3.向分類添加屬性
4.消息轉發(熱更新)解決Bug(JSPatch)