深入探究SEL,Method,IMP

SEL

  • SEL方法選擇器,表示一個(gè)selector的指針
  • 無(wú)論什么類里,只要方法名相同,SEL就相同。項(xiàng)目里的所有SEL都保存在一個(gè)NSSet集合里(NSSet集合里的元素不能重復(fù)),所以查找對(duì)應(yīng)方法,只要找到對(duì)應(yīng)的SEL就可以了。
  • SEL實(shí)際是根據(jù)方法名hash化了的字符串
SEL sel_registerName(const char *str)//向runtime system注冊(cè)一個(gè)方法名。如果方法名已經(jīng)注冊(cè),則放回已經(jīng)注冊(cè)的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ù)

// 比較兩個(gè)選擇器
BOOL sel_isEqual ( SEL lhs, SEL rhs );
//判斷方法名是否映射到某個(gè)函數(shù)實(shí)現(xiàn)上
BOOL sel_isMapped(SEL sel);
出現(xiàn)個(gè)BUG:

既然SEL是方法的唯一標(biāo)識(shí),那不同的類調(diào)用名字相同的方法怎么辦呢?

那就讓下一個(gè)重要任務(wù)出場(chǎng)吧。

IMP

定義:函數(shù)指針,指向方法實(shí)現(xiàn)的首地址。
代碼定義如下:

typedef id (*IMP)(id, SEL, ...); 

其參數(shù)包含id,SEL,后面試實(shí)際的參數(shù)列表。
那么,XX調(diào)用了XXX方法,其參數(shù)為XX都確定下來(lái)了。

IMP的高級(jí)作用

既然上述元素都確定下來(lái)了,那么就可以直接繞過(guò)Runtime的消息傳遞機(jī)制,直接執(zhí)行IMP指向的函數(shù)了。省去了一些列的查找,直接向?qū)ο蟀l(fā)送消息,效率會(huì)高一些。

IMP imp_implementationWithBlock(id block)//根據(jù)代碼塊獲取IMP,其實(shí)就是代碼塊與IMP關(guān)聯(lián)
IMP method_getImplementation(Method m) //根據(jù)Method獲取IMP
[[objc Class] instanceMethodForSelector:SEL]//根據(jù)OC方式獲取IMP

當(dāng)我們獲取一個(gè)方法的IMP時(shí)候可以直接調(diào)用IMP

IMP imp = method_getImplementation(Method m);
id objc = imp(id,SEL,argument);//objc用來(lái)保存方法的返回值,id表示調(diào)用這個(gè)方法的對(duì)象,SEL是Method的選擇器,argument是方法的參數(shù)。

Method

Method定義如下:它主要是用語(yǔ)描述類里面的方法

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;//方法的實(shí)現(xiàn)
}    

從上述代碼可以看出,Method是一個(gè)結(jié)構(gòu)體,包含了SEL和IMP成員變量。
實(shí)際上,相當(dāng)于在SEL和IMP之間做了一個(gè)映射,有了Method,SEL就可以找到對(duì)應(yīng)的IMP,從而調(diào)用方法。

Method操作函數(shù)如下:
方法操作主要有以下函數(shù):
// 添加方法
BOOL class_addMethod ( Class cls, SEL name, IMP imp, const char *types );

// 獲取實(shí)例方法
Method class_getInstanceMethod ( Class cls, SEL name );

// 獲取類方法
Method class_getClassMethod ( Class cls, SEL name );

// 獲取所有方法的數(shù)組
Method * class_copyMethodList ( Class cls, unsigned int *outCount );

// 替代方法的實(shí)現(xiàn)
IMP class_replaceMethod ( Class cls, SEL name, IMP imp, const char *types );

// 返回方法的具體實(shí)現(xiàn)
IMP class_getMethodImplementation ( Class cls, SEL name );
IMP class_getMethodImplementation_stret ( Class cls, SEL name );

// 類實(shí)例是否響應(yīng)指定的selector
BOOL class_respondsToSelector ( Class cls, SEL sel );

此處具體實(shí)現(xiàn)比較簡(jiǎn)單,可以通過(guò)手動(dòng)操作IMP來(lái)完成方法的調(diào)用。

實(shí)例代碼:

#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];
}

//定義一個(gè)block
//手動(dòng)添加方法
- (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); //因?yàn)榉椒愋拖嗤ǘ际菬o(wú)參數(shù)無(wú)返回值類型,所以方法類型相同,如果知道的話,可以直接制定type為v16@0:8)
    sel_registerName("newSel");             //注冊(cè)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

補(bǔ)充:

  1. 在swift里可以使用#selector(XXX)來(lái)獲取對(duì)應(yīng)的SEL,但這并非指swift的方法調(diào)用是通過(guò)selector來(lái)實(shí)現(xiàn)的,能調(diào)用僅僅是因?yàn)閟wift和OC的混編;
  2. 每個(gè)方法名有對(duì)應(yīng)的唯一seletor,其SEL相同,但對(duì)應(yīng)的IMP函數(shù)指針不同。

Github源碼地址

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 2,069評(píng)論 0 9
  • 繼上Runtime梳理(四) 通過(guò)前面的學(xué)習(xí),我們了解到Objective-C的動(dòng)態(tài)特性:Objective-C不...
    小名一峰閱讀 848評(píng)論 0 3
  • 本文轉(zhuǎn)載自:http://yulingtianxia.com/blog/2014/11/05/objective-...
    ant_flex閱讀 888評(píng)論 0 1
  • 一、Runtime簡(jiǎn)介 Runtime簡(jiǎn)稱運(yùn)行時(shí)。OC就是運(yùn)行時(shí)機(jī)制,也就是在運(yùn)行時(shí)候的一些機(jī)制,其中最主要的是消...
    林安530閱讀 1,118評(píng)論 0 2
  • 參考鏈接: http://www.cnblogs.com/ioshe/p/5489086.html 簡(jiǎn)介 Runt...
    樂(lè)樂(lè)的簡(jiǎn)書閱讀 2,249評(píng)論 0 9

友情鏈接更多精彩內(nèi)容