轉(zhuǎn)自大神之作:http://blog.devwu.com/develop/2014-08-19/objcruntime-explore4/
前言
在這一篇中,我們來聊一聊runtime中method
定義
先來看一下method
相關(guān)的定義
typedef struct objc_method *Method;
typedef struct objc_selector *SEL;
typedef void (*IMP)(void /* id,SEL, ... */ );
//方法描述
struct objc_method_description {
SEL name; //方法名稱
char *types; //參數(shù)類型字符串
};
//以下代碼是 ObjC2.0 之前method的定義
struct objc_method {
SEL method_name;
char *method_types;
IMP method_imp;
}
里邊有三個(gè)類型別名,在這兒先解釋一下
SEL selector的簡寫,俗稱方法選擇器,實(shí)質(zhì)存儲(chǔ)的是方法的名稱
IMP implement的簡寫,俗稱方法實(shí)現(xiàn),看源碼得知它就是一個(gè)函數(shù)指針
Method 對(duì)上述兩者的一個(gè)包裝結(jié)構(gòu).
函數(shù)
method相關(guān)的函數(shù)也不是太多,下邊簡單羅列說明一下
//判斷類中是否包含某個(gè)方法的實(shí)現(xiàn)
BOOL class_respondsToSelector(Class cls, SEL sel)
//獲取類中的方法列表
Method *class_copyMethodList(Class cls, unsigned int *outCount)
//為類添加新的方法,如果方法該方法已存在則返回NO
BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types)
//替換類中已有方法的實(shí)現(xiàn),如果該方法不存在添加該方法IMP
class_replaceMethod(Class cls, SEL name, IMP imp, const char *types)
//獲取類中的某個(gè)實(shí)例方法(減號(hào)方法)
Method class_getInstanceMethod(Class cls, SEL name)
//獲取類中的某個(gè)類方法(加號(hào)方法)
Method class_getClassMethod(Class cls, SEL name)
//獲取類中的方法實(shí)現(xiàn)IMP class_getMethodImplementation(Class cls, SEL name)
//獲取類中的方法的實(shí)現(xiàn),該方法的返回值類型為struct
IMP class_getMethodImplementation_stret(Class cls, SEL name)
//獲取Method中的SEL
SEL method_getName(Method m)
//獲取Method中的IMP
IMP method_getImplementation(Method m)
//獲取方法的Type字符串(包含參數(shù)類型和返回值類型)
const char *method_getTypeEncoding(Method m)
//獲取參數(shù)個(gè)數(shù)
unsigned int method_getNumberOfArguments(Method m)
//獲取返回值類型字符串
char *method_copyReturnType(Method m)
//獲取方法中第n個(gè)參數(shù)的Type
char *method_copyArgumentType(Method m, unsigned int index)
//獲取Method的描述
struct objc_method_description *method_getDescription(Method m)
//設(shè)置Method的IMP
IMP method_setImplementation(Method m, IMP imp)
//替換Method
void method_exchangeImplementations(Method m1, Method m2)
//獲取SEL的名稱
const char *sel_getName(SEL sel)
//注冊(cè)一個(gè)SEL
SEL sel_registerName(const char *str)
//判斷兩個(gè)SEL對(duì)象是否相同
BOOL sel_isEqual(SEL lhs, SEL rhs)
//通過塊創(chuàng)建函數(shù)指針,block的形式為^ReturnType(id self,參數(shù),...)
IMP imp_implementationWithBlock(id block)
//獲取IMP中的block
id imp_getBlock(IMP anImp)
//移出IMP中的block
BOOL imp_removeBlock(IMP anImp)
//調(diào)用target對(duì)象的sel方法
id objc_msgSend(id target, SEL sel, 參數(shù)列表...)
Showtime
下邊就來玩玩runtime API中的method相關(guān)操作
//創(chuàng)建繼承自NSObject類的People類
Class People = objc_allocateClassPair([NSObject class], "People", 0);
//將People類注冊(cè)到runtime中
objc_registerClassPair(People);
//注冊(cè)test: 方法選擇器
SEL sel = sel_registerName("test:");
//函數(shù)實(shí)現(xiàn)
IMP imp = imp_implementationWithBlock(^(id this,id args,...){
NSLog(@"方法的調(diào)用者為 %@",this);
NSLog(@"參數(shù)為 %@",args);
return @"返回值測試";
});
//向People類中添加 test:方法;函數(shù)簽名為@@:@,
// 第一個(gè)@表示返回值類型為id,
// 第二個(gè)@表示的是函數(shù)的調(diào)用者類型,
// 第三個(gè):表示 SEL
// 第四個(gè)@表示需要一個(gè)id類型的參數(shù)
class_addMethod(People, sel, imp, "@@:@");
//替換People從NSObject類中繼承而來的description方法
class_replaceMethod(
People,
@selector(description),
imp_implementationWithBlock(^NSString*(id this,...){ return @"我是Person類的對(duì)象";}),
"@@:");
//完成
[[People alloc]init];id p1 = objc_msgSend(objc_msgSend(People, @selector(alloc)),@selector(init));
//調(diào)用p1的sel選擇器的方法,并傳遞@"???"作為參數(shù)
id result = objc_msgSend(p1, sel,@"???");
//輸出sel方法的返回值
NSLog(@"sel 方法的返回值為 : %@",result);
//獲取People類中實(shí)現(xiàn)的方法列表
NSLog(@"輸出People類中實(shí)現(xiàn)的方法列表");
unsigned int methodCount;
Method * methods = class_copyMethodList(People, &methodCount);
for (int i = 0; i<methodCount; i++) {
NSLog(@"方法名稱:%s",sel_getName(method_getName(methods[i])));
NSLog(@"方法Types:%s",method_getDescription(methods[i])->types);
}
free(methods);
輸出
2014-08-20 00:03:38.496 Test[99505:303] 方法的調(diào)用者為 我是Person類的對(duì)象
2014-08-20 00:03:38.498 Test[99505:303] 參數(shù)為 ???
2014-08-20 00:03:38.498 Test[99505:303] sel 方法的返回值為 : 返回值測試
2014-08-20 00:03:38.499 Test[99505:303] 輸出People類中實(shí)現(xiàn)的方法列表
2014-08-20 00:03:38.499 Test[99505:303] 方法名稱:description
2014-08-20 00:03:38.499 Test[99505:303] 方法Types:@@:
2014-08-20 00:03:38.500 Test[99505:303] 方法名稱:test:
2014-08-20 00:03:38.500 Test[99505:303] 方法Types:@@:@