SEL、IMP、Method之間的關系:一個類(Class)持有一個分發表,在運行期分發訊息,表中的每一個物體代表一個方法(Method),它的名字叫做選擇子(SEL),對應著一種方法實作(IMP),具體的分析如下:
參考蘋果官方公開原始碼
objc4原始碼在線瀏覽
objc4原始碼下載
1、SEL
在上述蘋果官網公開原始碼objc4的objc.h檔案中,定義如下:
/// An opaque type that represents a method selector.
typedef struct objc_selector *SEL;
SEL:方法選擇器(翻譯成中文叫做選擇子或者選擇器),表示一個selector的指標,代表方法的名稱,僅以名字來識別,
SEL代表方法在Runtime期間的識別符號,為SEL型別,雖然SEL是objc_selector結構體指標,但實際上它只是一個C字串,
在類加載的時候,編譯器會生成與方法相對應的選擇子,并注冊到Objective-C的Runtime運行系統,
無論什么類里,無論類是否存在依存關系,只要方法名相同,SEL就相同,
專案里的所有SEL都保存在一個NSSet集合里(NSSet集合里的元素不能重復),所以查找對應方法,只要找到對應的SEL就可以了,
SEL實際是根據方法名hash化了的字串
SEL sel_registerName(const char *str)//向runtime system注冊一個方法名,如果方法名已經注冊,則放回已經注冊的SEL
SEL sel_getUid(const char *str)//同上
@selector(<#selector#>)//oc編譯器提供的
SEL NSSelectorFromString(NSString *aSelectorName)//OC字串轉化
SEL method_getName ( Method m );//根據Method結構體獲取
SEL的操作函式
// 比較兩個選擇器
BOOL sel_isEqual ( SEL lhs, SEL rhs );
//判斷方法名是否映射到某個函式實作上
BOOL sel_isMapped(SEL sel);
雖然SEL是方法的唯一標識,但不同的類呼叫名字相同的方法應該如何處理,接下來就要用到IMP
2、IMP
代碼定義:
/// A pointer to the function of a method implementation.
#if !OBJC_OLD_DISPATCH_PROTOTYPES
typedef void (*IMP)(void /* id, SEL, ... */ );
#else
typedef id _Nullable (*IMP)(id _Nonnull, SEL _Nonnull, ...);
#endif
可以簡化為:
/// A pointer to the function of a method implementation.
typedef id (*IMP)(id, SEL , ...);
IMP:代表函式指標,指向方法實作的首地址,即函式執行的入口,
該函式使用標準的C呼叫,
第一個引數指向self(它代表當前類實體的地址,如果是類則指向的是它的元類),作為訊息的接受者;
第二個引數代表方法的選擇子;...代表可選引數,前面的id代表回傳值,
那么,XX呼叫了XXX方法,其引數為XX都確定下來了,
IMP的高級作用
既然上述元素都確定下來了,那么就可以直接繞過Runtime的訊息傳遞機制,直接執行IMP指向的函式了,省去了一些列的查找,直接向物件發送訊息,效率會高一些,
IMP imp_implementationWithBlock(id block)//根據代碼塊獲取IMP,其實就是代碼塊與IMP關聯
IMP method_getImplementation(Method m) //根據Method獲取IMP
[[objc Class] instanceMethodForSelector:SEL]//根據OC方式獲取IMP
獲取一個方法的IMP時候可以直接呼叫IMP
IMP imp = method_getImplementation(Method m);
id objc = imp(id,SEL,argument);//objc用來保存方法的回傳值,id表示呼叫這個方法的物件,SEL是Method的選擇器,argument是方法的引數,
3、Method
runtime.h檔案中,代碼定義如下:
/// An opaque type that represents a method in a class definition.
typedef struct objc_method *Method;
objc_method結構體定義如下:
/// Method
struct objc_method {
SEL method_name OBJC2_UNAVAILABLE;//方法名
char *method_types OBJC2_UNAVAILABLE;//引數回傳值字串描述
IMP method_imp OBJC2_UNAVAILABLE;//方法的實作
}
Method:Method是一個objc_method結構體指標,該結構體中包含一個SEL和IMP,
實際上相當于在SEL和IMP之間作了一個映射,有了Method,SEL就可以找到對應的IMP,從而呼叫方法,對開發者來說是一種不透明的型別,被隱藏在我們平時書寫的類或物件的方法背后,
method_name:方法名,型別為SEL,前面提到過相同名字的方法即使在不同類中定義,它們的方法選擇器也相同,
method_types:方法型別,是個char指標,其實存盤著方法的引數型別和回傳值型別,即是Type Encoding編碼,
method_imp:指向方法的實作,本質上是一個函式的指標,就是前面講到的Implementation,
Method操作函式如下:
方法操作主要有以下函式:
// 添加方法
BOOL class_addMethod ( Class cls, SEL name, IMP imp, const char *types );
// 獲取實體方法
Method class_getInstanceMethod ( Class cls, SEL name );
// 獲取類方法
Method class_getClassMethod ( Class cls, SEL name );
// 獲取所有方法的陣列
Method * class_copyMethodList ( Class cls, unsigned int *outCount );
// 替代方法的實作
IMP class_replaceMethod ( Class cls, SEL name, IMP imp, const char *types );
// 回傳方法的具體實作
IMP class_getMethodImplementation ( Class cls, SEL name );
IMP class_getMethodImplementation_stret ( Class cls, SEL name );
// 類實體是否回應指定的selector
BOOL class_respondsToSelector ( Class cls, SEL sel );
class_addMethod的實作會覆寫父類的方法實作,但不會取代本類中已存在的實作,如果本類中包含一個同名的實作,則函式會回傳NO,如果要修改已存在實作,可以使用method_setImplementation 一個Objective-C方法是一個簡單的C函式,它至少包含兩個引數–self和_cmd,所以,我們的實作函式(IMP引數指向的函式)至少需要兩個引數
class_getInstanceMethod、class_getClassMethod函式,與class_copyMethodList不同的是,這兩個函式都會去搜索父類的實作,
class_copyMethodList函式,回傳包含所有實體方法的陣列,如果需要獲取類方法,則可以使用class_copyMethodList(object_getClass(cls), &count)(一個類的實體方法是定義在元類里面),該串列不包含父類實作的方法,outCount引數回傳方法的個數,在獲取到串列后,我們需要使用free()方法來釋放它,
class_replaceMethod函式,該函式的行為可以分為兩種:如果類中不存在name指定的方法,則類似于class_addMethod函式一樣會添加方法;如果類中已存在name指定的方法,則類似于method_setImplementation一樣替代原方法的實作,
class_getMethodImplementation函式,該函式在向類實體發送訊息時會被呼叫,并回傳一個指向方法實作函式的指標,這個函式會比method_getImplementation(class_getInstanceMethod(cls, name))更快,回傳的函式指標可能是一個指向runtime內部的函式,而不一定是方法的實際實作,例如,如果類實體無法回應selector,則回傳的函式指標將是運行時訊息轉發機制的一部分,
class_respondsToSelector函式,我們通常使用NSObject類的respondsToSelector:或instancesRespondToSelector:方法來達到相同目的,
參考文章
SEL、Method和IMP區別
深入探究SEL,Method,IMP
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/305491.html
標籤:其他
