iOS開發Runtime的理解與應用
一、Runtime概念
RunTime簡稱執行時,其中最主要的是訊息機制。
對於C語言,函式的呼叫在編譯的時候會決定呼叫哪個函式,編譯完成之後直接順序執行,無任何二義性。
OC的函式呼叫成為訊息傳送,屬於動態呼叫過程。在編譯的時候並不能決定真正呼叫哪個函式(事實證明,在編譯階段,OC可以呼叫任何函式,即使這個函式並未實現,只要宣告過就不會報錯。而C語言在編譯階段就會報錯)。
-
只有在真正執行的時候才會根據函式的名稱找到對應的函式來呼叫。
其動態性體現在三個方面:
1.動態型別:
即執行時再決定物件的型別。簡單說就是id型別,任何物件都可以被id指標所指,只有在執行時才能決定是什麼型別。像內建的明確的基本型別都屬於靜態型別(int、NSString等)。靜態型別在編譯的時候就能被識別出來。所以,若程式發生了型別不對應,編譯器就會發出警告。而動態型別就編譯器編譯的時候是不能被識別的,要等到執行時(run time),即程式執行的時候才會根據語境來識別。所以這裡面就有兩個概念要分清:編譯時跟執行時。
2.動態繫結:
基於動態型別,在某個例項物件被確定後,其型別便被確定了。該物件對應的屬性和響應的訊息也被完全確定,這就是動態繫結。比如我們一般向一個NSObject物件傳送-respondsToSelector:或者 -instancesRespondToSelector:等來確定物件是否可以對某個SEL做出響應,而在OC訊息轉發機制被觸發之前,對應的類 的+resolveClassMethod:和+resolveInstanceMethod:將會被呼叫,在此時有機會動態地向類或者例項新增新的方 法,也即類的實現是可以動態繫結的;isKindOfClass也是一樣的道理。
3.動態載入:
所謂動態載入就是我們做開發的時候icon圖片的時候在Retina裝置上要多新增一個張@2x的圖片,當裝置更換的時候,圖片也會自動的替換。
二、Runtime資料結構
1.Class
Objective-C類是由Class型別來表示,Class 其實是指向 objc_class 結構體的指標
typedef struct objc_class *Class;
我們可以從<objc/runtime.h>裡面看到類的定義
struct object_class{
Class isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
Class super_class OBJC2_UNAVAILABLE; // 父類
const char *name OBJC2_UNAVAILABLE; // 類名
long version OBJC2_UNAVAILABLE; // 類的版本資訊,預設為0
long info OBJC2_UNAVAILABLE; // 類資訊,供執行期使用的一些位標識
long instance_size OBJC2_UNAVAILABLE; // 該類的例項變數大小
struct objc_ivar_list *ivars OBJC2_UNAVAILABLE; // 該類的成員變數連結串列
struct objc_method_list *methodLists OBJC2_UNAVAILABLE; // 方法定義的連結串列
struct objc_cache *cache OBJC2_UNAVAILABLE; // 方法快取
struct objc_protocol_list *protocols OBJC2_UNAVAILABLE; // 協議連結串列
#endif
}OBJC2_UNAVAILABLE;
2.id
id 是一個結構體指標型別,它可以指向 Objective-C 中的任何物件。從<objc/objc.h>中可以看出id其實是指向objc_object結構體的指標。objc_object只有一個成員變數 isa,物件可以通過 isa 指標找到其所屬的類,這也是為什麼id可以表示任意物件的原因。isa 是一個 Class 型別的成員變數。
注意:在KVO中,isa在執行時會被修改,指向一箇中間類,對於編譯器而言,isa的指向才是最真實的型別。
/// Represents an instance of a class.
struct objc_object {
Class _Nonnull isa OBJC_ISA_AVAILABILITY;
};
/// A pointer to an instance of a class.
typedef struct objc_object *id;
當我們向一個Objective-C物件傳送訊息時,執行時庫會根據
例項物件的isa指標找到這個例項物件所屬的類。Runtime庫會在類的方法列表由super_class指標找到父類的方法列表直至根類NSObject中去尋找與訊息對應的selector指向的方法,找到後即執行這個方法。
3.元類(meta-Class)
類自身也是一種物件,可以叫做“類物件”。類物件包含一個指向其類的一個isa指標( Class _Nonnull isa )
為了呼叫類方法,這個類的isa指標必須指向一個包含這些類方法的一個objc_class結構體。這就引出了meta-class的概念,meta-class中儲存著一個類的所有類方法。
所以,呼叫類方法的這個類物件的isa指標指向的就是meta-class。當我們向一個物件傳送訊息時,runtime會在這個物件所屬的這個類的方法列表中查詢方法;而向一個類傳送訊息時,會在這個類的meta-class的方法列表中查詢。
下圖是一個經典的類及相應meta-class類的一個繼承體系圖解:
從圖中可以看出:
1.每個例項物件的類都是類物件,每個類物件的類都是元類物件,每個元類物件的類都是根元類(root meta class的isa指向自身)。即任何NSObject繼承體系下的meta-class都使用NSObject的meta-class作為自己的所屬類,而基類的meta-class的isa指標是指向它自己。
2.類物件的父類最終繼承自根類物件NSObject,NSObject的父類為nil
3.元類物件(包括根元類)的父類最終繼承自根類物件NSObject
三、方法和訊息
1.SEL
typedef struct objc_selector *SEL;
SEL sel1 = @selector(func1);
SEL sel2 = NSSelectorFromString(func2);
SEL本質上是一個指向方法的指標。Objective-C在編譯時,會依據每一個方法的名字、引數序列,生成一個唯一的整型標識即SEL,每一個方法都對應著一個SEL。所以即使返回值型別或引數型別不同,方法名相同也會報錯。
2.IMP
id (*IMP)(id, SEL,...)
IMP的本質是函式指標,指向方法實現的地址,直接通過IMP就可以找到各個方法。這樣效率更高,因為繞過了訊息傳遞階段,直接定位。
SEL就是為了查詢方法的最終實現IMP的。由於每個方法對應唯一的SEL,因此我們可以通過SEL方便快速準確地獲得它所對應的IMP。
訊息傳送和轉發流程可以概括為:訊息傳送(Messaging)是 Runtime 通過 selector 快速查詢 IMP 的過程,有了函式指標就可以執行對應的方法實現;訊息轉發(Message Forwarding)是在查詢 IMP 失敗後執行一系列轉發流程的慢速通道,如果不作轉發處理,則會打日誌和丟擲異常。
3.Method
typedef struct objc_method *Method
struct objc_method{
SEL method_name OBJC2_UNAVAILABLE; // 方法名
char *method_types OBJC2_UNAVAILABLE;
IMP method_imp OBJC2_UNAVAILABLE; // 方法實現
}
可以看出method包含SEL和IMP,在實現方法交換時,主要原理就是交換SEL和IMP的對映關係。
參考:https://www.jianshu.com/p/46dd81402f63
https://www.jianshu.com/p/adf0d566c887
https://www.jianshu.com/p/13457a27624c
相關文章
- iOS Runtime 初識與應用iOS
- 玩轉iOS開發:裝逼技術RunTime的應用(一)iOS
- 【iOS開發進階】-RunTimeiOS
- Runtime-iOS執行時應用篇iOS
- iOS開發·runtime原理與實踐: 基本知識篇iOS
- 玩轉iOS開發:iOS開發中的裝逼技術 – RunTime(一)iOS
- 玩轉iOS開發:iOS開發中的裝逼技術 – RunTime(二)iOS
- iOS開發之runtime(一):runtime除錯環境搭建iOS除錯
- iOS 開發中 runtime 常用的幾種方法iOS
- ios runtime之Method Swizzling及其應用場景iOS
- iOS runtime執行時的作用和應用場景iOS
- Go GPM的理解 與 runtime包Go
- iOS 開發:『Runtime』詳解(二)Method SwizzlingiOS
- Flutter與Native混合開發-FlutterBoost整合應用和開發實踐(iOS)FlutteriOS
- AsyncTask的理解與應用
- Appcode 2022 for mac(ios應用開發)APPMaciOS
- iOS底層原理 runtime - super、hook、以及簡單應用--(8)iOSHook
- iOS 開發:『Runtime』詳解(三)Category 底層原理iOSGo
- iOS 開發:『Runtime』詳解(一)基礎知識iOS
- IOS 逆向開發(三)應用簽名iOS
- AppCode 2022 for mac(ios應用開發)中文APPMaciOS
- DockerFile理解與應用Docker
- Runtime理解
- 玩轉iOS開發:裝逼技術RunTime的總結篇iOS
- ios應用開發+swift語言入門iOSSwift
- 鴻蒙 Android iOS 應用開發對比02鴻蒙AndroidiOS
- iOS RunTime 總結iOS
- iOS Runtime詳解iOS
- python閉包 - 理解與應用Python
- 官方翻譯 | 有關基於文件的iOS應用開發iOS
- iOS VoIP電話:CallKit與PushKit的應用iOS
- 【主流技術】Mybatis Plus的理解與應用MyBatis
- BizWorks助力企業應用的高效開發與複用
- 白話 Ruby 與 DSL 以及在 iOS 開發中的運用iOS
- 帶你瞭解 WebAssembly 的發展、應用與開發Web
- iOS 開發:『Runtime』詳解(四)獲取類詳細屬性、方法iOS
- iOS 防止Crash之runtimeiOS
- iOS 11開發教程(二十二)iOS11應用檢視實現按鈕的響應(2)iOS