在 ios開發(fā) Runtime 詳解part1中我已經(jīng)解釋了Introspection,接下來介紹Runtime的其它特性。
Runtime能做什么?
1承绸、Introspection, 獲得對(duì)象中的信息,如Class, Selector(SEL), Method:
2挣轨、Dynamic Method Resolution (動(dòng)態(tài)方法解析)
在蘋果的文檔里給出了一個(gè)動(dòng)態(tài)添加c方法的例子: 例子军熏, 我在這里做一些擴(kuò)展:
首先我在RuntimeObject.h類中添加三個(gè)方法:
- (void)addInstanceMethod: (NSString *)str; // 添加實(shí)例方法
+ (void)addClassMethod: (NSString *)str; // 添加類方法
- (void)addCMethod; // 添加c方法
在RuntimeObject.m中我們有三個(gè)方法:
/**
動(dòng)態(tài)綁定的實(shí)例方法
@param str 傳遞的參數(shù)
*/
- (void)instanceMethod: (NSString *)str {
NSLog(@"execute instance Method, pass value: %@", str);
}
/**
動(dòng)態(tài)綁定的類方法
@param str 傳遞的參數(shù)
*/
+ (void)classMethod: (NSString *)str {
NSLog(@"execute class Method, pass value: %@", str);
}
/**
動(dòng)態(tài)綁定的c方法, 至少包含self和_cmd兩個(gè)參數(shù)
@param self c方法必須傳遞
@param _cmd c方法必須傳遞
*/
void dynamicMethodIMP(id self, SEL _cmd) {
printf("execute C Method");
}
現(xiàn)在我們需要通過調(diào)用.h文件里的方法來執(zhí)行.m里對(duì)應(yīng)綁定的方法:
[ro addInstanceMethod: @"instance method"];
[RuntimeObject addClassMethod: @"class method"];
[ro addCMethod];
此時(shí)調(diào)用一定是會(huì)出錯(cuò)的卷扮,因?yàn)槲覀冞€沒有進(jìn)行動(dòng)態(tài)綁定羞迷,要綁定RuntimeObject.m中的三個(gè)方法,我們需要借助實(shí)現(xiàn)resolveInstanceMethod和resolveClassMethod這兩個(gè)方法來動(dòng)態(tài)添加我們需要綁定的方法:
+ (BOOL)resolveInstanceMethod:(SEL)aSEL{
if (aSEL == @selector(addInstanceMethod:)) {
class_addMethod([self class], aSEL, class_getMethodImplementation([self class], @selector(instanceMethod:)), "v@:");
NSLog(@"%@", @"dynamicMethodIMP added");
return YES;
} else if (aSEL == @selector(addCMethod)) {
class_addMethod([self class], aSEL, (IMP) dynamicMethodIMP, "v@:");
return YES;
}
return [super resolveClassMethod:aSEL];
}
+ (BOOL)resolveClassMethod:(SEL)aSEL {
if (aSEL == @selector(addClassMethod:)) {
class_addMethod(object_getClass(self), aSEL, class_getMethodImplementation(object_getClass(self), @selector(classMethod:)), "v@:");
return YES;
}
return [super resolveClassMethod:aSEL];
}
要注意画饥,添加實(shí)例方法和類方法均是調(diào)用了runtime里class_addMeghod方法衔瓮,這個(gè)方法結(jié)構(gòu)如下:
BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types);
cls: 是要將方法添加到的目標(biāo)類
name: 是一個(gè)selector,指定添加的方法的名字
imp: 實(shí)現(xiàn)的新方法抖甘,必須包含self和_cmd兩個(gè)參數(shù)热鞍,由于oc的方法中默認(rèn)有這兩個(gè)參數(shù),在代碼中不必特別添加衔彻,但是c的方法需要加上這兩個(gè)參數(shù)薇宠。
types: 描述參數(shù)的類型,由于方法都含有self和_cmd兩個(gè)參數(shù)艰额,第二個(gè)字符一定是@"", 而第一個(gè)字符表示返回值的類型澄港, 我們這里因?yàn)榉祷刂凳莢oid就用v表示,第三個(gè)字符表示一個(gè)方法的selector柄沮,我們放':'來表示回梧,所以types傳入"v@:",此處類型的編碼可以在這里查看: 類型編碼
要注意的是當(dāng)self是類對(duì)象的時(shí)候祖搓,調(diào)用[self class]返回的是self狱意,要獲得class,需要通過object_getClass(self)來獲得拯欧,否則會(huì)出錯(cuò)详囤。
動(dòng)態(tài)方法解析可以讓我們像對(duì)屬性修飾@dynamic一樣,不讓系統(tǒng)提供實(shí)現(xiàn)的方法镐作,自定義方法的實(shí)現(xiàn)藏姐,也可以用來綁定c的方法來進(jìn)行實(shí)現(xiàn)隆箩,一旦綁定,我們也可以用performSelector來直接調(diào)用.m里綁定的方法:
[ro addInstanceMethod: @"instance method"]; // 動(dòng)態(tài)綁定了instanceMethod:方法
if ([ro respondsToSelector: @selector(instanceMethod:)]) {
[ro performSelector:@selector(instanceMethod:) withObject:@"call instance method"];
// 輸出: execute instance Method, pass value: call instance method
}
此文介紹了Dynamic Method Resolution (動(dòng)態(tài)方法解析)的用法羔杨,希望能對(duì)你有所幫助捌臊。