Objective-C之Class类型、选择器Selector以及函数指针(ZZ)

我们在实际上的编程过程中,也许会遇到这样的场景,那就是我们在写程序的时候不能确切的知道我们需要使用什么类,使用这个类的什么方法。在这个时候,我们需要在我们的程序里面动态的根据用户的输入来创建我们在写程序不知道的类的对象,并且调用这个对象的实例方法。Objective-C 为我们提供了Class 类型, 选择器Selector 以及指针函数来实现这样的需求,从而大大的提高了我们程序的动态性能。

在Objective-C 里面,一个类被正确的编译过后,在这个编译成功的类里面,存在一个变量用于保存这个类的信息。我们可以通过一个普通的字符串取得这个Class,也可以通过我们生成的对象取得这个Class。Class 被成功取得之后,我们可以把这个Class 当作一个已经定义好的类来使用它。

Selector 和Class 比较类似,不同的地方是Selector 用于表示方法。在Objective-C 的程序进行编译的时候,会根据方法的名字(包括参数列表)确定一个唯一的身份证明(实际上就是一个整数),不用的类里面的相同名字相同声明的方法的身份证明是一样的。这样在程序执行的时候,runtime 就不用费力的进行方法的名字比较来确定是执行哪一个方法了,只是通过一个整数的寻找就可以马上定位到相应的方法,然后找到相应的方法的入口地址,这样方法就可以被执行了。

在Objective-C 里面消息也就是方法的执行比C 语言的直接找到函数入口地址执行的方式,从效率上来讲是比较低下的。当我们需要执行效率的时候,比如说在一个很大的循环当中需要执行某个功能的时候,我们可以放弃向对某一个对象发送消息的手段,用指针函数取而代之,这样就可以获得和C 语言一样的执行效率了。

DoProxy.h
#define SET_SKIN_COLOR @"setSkinColor:"  #define BULL_CLASS @"Bull"  #define CATTLE_CLASS @"Cattle"  @interface DoProxy : NSObject {  BOOL notFirstRun;  id cattle[3];  SEL say;  SEL skin;  void(*setSkinColor_Func) (id, SEL, NSString*);  IMP say_Func;  Class bullClass;  }  - (void) doWithCattleId:(id) aCattle colorParam:(NSString*) color;  - (void) setAllIVars;  - (void) SELFuncs;  - (void) functionPointers;  @end  

1. BOOL是布尔类型,YES 是1,NO 是0
2. Objective-C 在编译的时候,会根据方法的名字(包括参数序列),生成一个用来区分这个方法的唯一的一个ID,这个ID就是SEL 类型的。
SEL的使用方法:
为SEL变量赋值:
(1) SEL 变量名= @selector( 方法名字);
(2) SEL 变量名=NSSelectorFromString( 方法名字的字符串);
利用SEL发消息:
[对象performSelector:SEL 变量withObject:参数1 withObject:参数2];
3. 函数指针的数值是函数的入口地址。可以通过SEL取得函数指针。我们取得了函数指针之后,也就意味着我们取得了执行的时候的这段方法的代码的入口。
a) void(*setSkinColor_Func) (id, SEL, NSString*);的解读:
(1) 第一个参数是id 类型的,就是消息的接受对象,在执行的时候这个id 实际上就是self,因为我们将要向某个对象发送消息。
(2) 第二个参数是SEL,也是方法的ID。方法的定义体里面,我们可以通过访问_cmd 得到这个方法自己的SEL。
(3) 第三个参数是NSString*类型的,我们用它来传递skin color。
(4) 在Objective-C 的函数指针里面,只有第一个id 和第二个SEL 是必需的,后面的参数有还是没有,如果有那么有多少个要取决于方法的声明。
b) IMP是一种比较简单的取得函数指针的新的定义方法。因为IMP的定义就是typedef id (*IMP)(id, SEL, );
4. 类在Objective-C 也为我们准备了类似的机制:Class 类型。当一个类被正确的编译过后,在这个编译成功的类里面,存在一个变量用于保存这个类的信息。我们可以通过一个普通的字符串取得这个Class,也可以通过我们生成的对象取得这个Class。Class被成功取得之后,我们可以把这Class 当作一个已经定义好的类来使用它。这样的机制允许我们在程序执行的过程当中,可以利用Class 来得到对象的类,也可以在程序执行的阶段动态的生成一个在编译阶段无法确定的一个对象。
Class的使用方法:
(1) Class 变量名= [类或者对象class];
(2) Class 变量名= NSClassFromString(方法名字的字符串);

DoProxy.m
#import "DoProxy.h"  #import "Cattle.h"  #import "Bull.h"  @implementation DoProxy  - (void) setAllIVars{  cattle[0] = [Cattle new];  bullClass = NSClassFromString(BULL_CLASS);  cattle[1] = [bullClass new];  cattle[2] = [bullClass new];  say = @selector(saySomething);  skin = NSSelectorFromString(SET_SKIN_COLOR);  }  - (void) SELFuncs{  [self doWithCattleId:cattle[0] colorParam:@"brown"];  [self doWithCattleId:cattle[1] colorParam:@"red"];  [self doWithCattleId:cattle[2] colorParam:@"black"];  [self doWithCattleId:self colorParam:@"haha"];  }  - (void) functionPointers{  setSkinColor_Func=(void (*)(id, SEL, NSString*))  [cattle[1] methodForSelector:skin];  //IMP setSkinColor_Func = [cattle[1] methodForSelector:skin];  say_Func = [cattle[1] methodForSelector:say];  setSkinColor_Func(cattle[1],skin,@"verbose");  NSLog(@"Running as a function pointer will be more efficiency!");  say_Func(cattle[1],say);   }  - (void) doWithCattleId:(id) aCattle colorParam:(NSString*) color{  if(notFirstRun == NO) {  NSString *myName = NSStringFromSelector(_cmd);  NSLog(@"Running in the method of %@", myName);  notFirstRun = YES;  }  NSString *cattleParamClassName = [aCattle className];  if([cattleParamClassName isEqualToString:BULL_CLASS] ||  [cattleParamClassName isEqualToString:CATTLE_CLASS]){   [aCattle setLegsCount:4];  if([aCattle respondsToSelector:skin]){  [aCattle performSelector:skin withObject:color];  }else{  NSLog(@"Hi, I am a %@, have not setSkinColor!", cattleParamClassName);  }  [aCattle performSelector:say];  }else{  NSString *yourClassName = [aCattle className];  NSLog(@"Hi, you are a %@, but I like cattle or bull!", yourClassName);  }  }  @end  


Hello Selector.m
#import <Foundation/Foundation.h>  #import "DoProxy.h"  int main (int argc, const char * argv[]){  NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];  DoProxy *doProxy = [DoProxy new];  [doProxy setAllIVars];  [doProxy SELFuncs];  [doProxy functionPointers];  [pool drain];  return 0;  }  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值