SEL
- SEL方法選擇器,表示一個selector的指針
- 無論什么類里,只要方法名相同,SEL就相同誉察。項目里的所有SEL都保存在一個NSSet集合里(NSSet集合里的元素不能重復),所以查找對應方法惹谐,只要找到對應的SEL就可以了持偏。
- SEL實際是根據(jù)方法名hash化了的字符串
SEL sel_registerName(const char *str)//向runtime system注冊一個方法名。如果方法名已經(jīng)注冊氨肌,則放回已經(jīng)注冊的SEL
SEL sel_getUid(const char *str)//同上
@selector(<#selector#>)//oc編譯器提供的
SEL NSSelectorFromString(NSString *aSelectorName)//OC字符串轉(zhuǎn)化
SEL method_getName ( Method m );//根據(jù)Method結(jié)構(gòu)體獲取
等等
SEL的操作函數(shù)
// 比較兩個選擇器
BOOL sel_isEqual ( SEL lhs, SEL rhs );
//判斷方法名是否映射到某個函數(shù)實現(xiàn)上
BOOL sel_isMapped(SEL sel);
出現(xiàn)個BUG:
既然SEL是方法的唯一標識鸿秆,那不同的類調(diào)用名字相同的方法怎么辦呢?
那就讓下一個重要任務出場吧怎囚。
IMP
定義:函數(shù)指針谬莹,指向方法實現(xiàn)的首地址。
代碼定義如下:
typedef id (*IMP)(id, SEL, ...);
其參數(shù)包含id,SEL,后面試實際的參數(shù)列表桩了。
那么,XX調(diào)用了XXX方法埠戳,其參數(shù)為XX都確定下來了井誉。
IMP的高級作用
既然上述元素都確定下來了,那么就可以直接繞過Runtime的消息傳遞機制整胃,直接執(zhí)行IMP指向的函數(shù)了颗圣。省去了一些列的查找,直接向?qū)ο蟀l(fā)送消息,效率會高一些在岂。
IMP imp_implementationWithBlock(id block)//根據(jù)代碼塊獲取IMP,其實就是代碼塊與IMP關聯(lián)
IMP method_getImplementation(Method m) //根據(jù)Method獲取IMP
[[objc Class] instanceMethodForSelector:SEL]//根據(jù)OC方式獲取IMP
當我們獲取一個方法的IMP時候可以直接調(diào)用IMP
IMP imp = method_getImplementation(Method m)奔则;
id objc = imp(id,SEL,argument);//objc用來保存方法的返回值,id表示調(diào)用這個方法的對象蔽午,SEL是Method的選擇器易茬,argument是方法的參數(shù)。
Method
Method定義如下:它主要是用語描述類里面的方法
typedef struct objc_method *Method;
objc_method結(jié)構(gòu)體定義如下
struct objc_method {
SEL method_name OBJC2_UNAVAILABLE;//方法名
char *method_types OBJC2_UNAVAILABLE;//參數(shù)返回值字符串描述
IMP method_imp OBJC2_UNAVAILABLE;//方法的實現(xiàn)
}
從上述代碼可以看出及老,Method是一個結(jié)構(gòu)體抽莱,包含了SEL和IMP成員變量。
實際上骄恶,相當于在SEL和IMP之間做了一個映射食铐,有了Method,SEL就可以找到對應的IMP僧鲁,從而調(diào)用方法虐呻。
Method操作函數(shù)如下:
方法操作主要有以下函數(shù):
// 添加方法
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 );
// 獲取所有方法的數(shù)組
Method * class_copyMethodList ( Class cls, unsigned int *outCount );
// 替代方法的實現(xiàn)
IMP class_replaceMethod ( Class cls, SEL name, IMP imp, const char *types );
// 返回方法的具體實現(xiàn)
IMP class_getMethodImplementation ( Class cls, SEL name );
IMP class_getMethodImplementation_stret ( Class cls, SEL name );
// 類實例是否響應指定的selector
BOOL class_respondsToSelector ( Class cls, SEL sel );
此處具體實現(xiàn)比較簡單,可以通過手動操作IMP來完成方法的調(diào)用寞秃。
實例代碼:
#import "OC_IMP.h"
typedef void (^CustomBlock)(NSString *name);
@interface OC_IMP ()
@property(nonatomic, weak) CustomBlock block;
@end
@implementation OC_IMP
- (void)testIMP {
[self addMethodByIMP];
}
//定義一個block
//手動添加方法
- (void)addMethodByIMP {
CustomBlock block = ^(NSString *name){
NSLog(@"執(zhí)行block");
};
IMP impBlock = imp_implementationWithBlock(block);
Method m = class_getInstanceMethod(self.class, @selector(testIMP));
method_setImplementation(m, impBlock);
const char * types = method_getTypeEncoding(m); //因為方法類型相同(都是無參數(shù)無返回值類型斟叼,所以方法類型相同,如果知道的話蜕该,可以直接制定type為v16@0:8)
sel_registerName("newSel"); //注冊newSel
BOOL isAdded = class_addMethod([self class], @selector(newSel), impBlock, types);
if (isAdded == YES) {
NSLog(@"添加成功");
[self performSelector:@selector(newSel)];
}
}
@end
OC_IMP *oc_imp = [[OC_IMP alloc] init];
[oc_imp testIMP];
調(diào)用執(zhí)行結(jié)果
2017-07-14 20:14:26.359 OCDeepLearning[5654:530015] 添加成功
2017-07-14 20:14:26.359 OCDeepLearning[5654:530015] 執(zhí)行block
補充:
- 在swift里可以使用#selector(XXX)來獲取對應的SEL,但這并非指swift的方法調(diào)用是通過selector來實現(xiàn)的犁柜,能調(diào)用僅僅是因為swift和OC的混編;
- 每個方法名有對應的唯一seletor,其SEL相同堂淡,但對應的IMP函數(shù)指針不同馋缅。