zoukankan      html  css  js  c++  java
  • ObjC(ObjectiveC)中的Class(类类型),Selector(选择器SEL),函数指针(IMP)

    作者:菩提树下的杨过
    出处:http://www.cnblogs.com/yjmyzz/archive/2011/02/28/1967451.html
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

    ObjC(Objective-C)中的Class(类类型),Selector(选择器SEL),函数指针(IMP)

    今天在园子里看到了一篇牛文“Objective-C 2.0 with Cocoa Foundation--- 5,Class类型,选择器Selector以及函数指针 ”,讲得十分精彩,忍不住把它的代码加上注释整理于此,以便日后查看。
    个人体会:obj-C中的“Class类型变量”比c#中的Object基类还要灵活,可以用它生成任何类型的实例(但是它又不是 NSObject)。而选择器SEL与函数指针IMP,如果非要跟c#扯上关系的话,这二个结合起来,就点类似c#中的反射+委托,可以根据一个方法名称 字符串,直接调用方法。
    "牛"的基类 Cattle.h
    1 #import <Foundation/Foundation.h>
    2  
    3 @interface Cattle : NSObject {
    4     int legsCount;
    5 }
    6 - (void)saySomething;
    7 - (void)setLegsCount:(int) count;
    8 @end
    Cattle.m
    01 #import "Cattle.h"
    02  
    03 @implementation Cattle
    04  
    05 -(void) saySomething
    06 {
    07     NSLog(@"Hello, I am a cattle, I have %d legs.", legsCount);
    08 }
    09  
    10 -(void) setLegsCount:(int) count
    11 {
    12     legsCount = count;
    13 }
    14 @end
    子类“公牛" Bull.h
    01 #import <Foundation/Foundation.h>
    02 #import "Cattle.h"
    03  
    04 @interface Bull : Cattle {
    05     NSString *skinColor;
    06 }
    07 - (void)saySomething;
    08 - (NSString*) getSkinColor;
    09 - (void) setSkinColor:(NSString *) color;
    10 @end
    Bull.m
    01 #import "Bull.h"
    02  
    03  
    04 @implementation Bull
    05  
    06 -(void) saySomething
    07 {
    08     NSLog(@"Hello, I am a %@ bull, I have %d legs.", [self getSkinColor],legsCount);
    09 }
    10  
    11 -(NSString*) getSkinColor
    12 {
    13     return skinColor;
    14 }
    15  
    16 - (void) setSkinColor:(NSString *) color
    17 {
    18     skinColor = color;
    19 }
    20 @end
    代理类DoProxy.h (关键的代码都在这里)
    01 #import <Foundation/Foundation.h>
    02  
    03 //定义几个字符串常量
    04 #define SET_SKIN_COLOR @"setSkinColor:"
    05 #define BULL_CLASS @"Bull"
    06 #define CATTLE_CLASS @"Cattle"
    07  
    08  
    09 @interface DoProxy : NSObject {
    10     BOOL notFirstRun;
    11      
    12     id cattle[3];
    13     //定义二个选择器
    14     SEL say;
    15     SEL skin;
    16      
    17     //定义一个函数指针(传统C语言的处理方式)
    18     void(*setSkinColor_Func)(id,SEL,NSString*);
    19      
    20     //定义一个IMP方式的函数指针(obj-C中推荐的方式)
    21     IMP say_Func;
    22      
    23     //定义一个类
    24     Class bullClass;
    25 }
    26  
    27 -(void) doWithCattleId:(id) aCattle colorParam:(NSString*) color;
    28 -(void) setAllIVars;
    29 -(void) SELFuncs;
    30 -(void) functionPointers;
    31  
    32 @end
    DoProxy.m
    01 #import "DoProxy.h"
    02 #import "Cattle.h"
    03 #import "Bull.h"
    04  
    05 @implementation DoProxy
    06  
    07  
    08 //初始化所有变量
    09 - (void) setAllIVars
    10 {  
    11     cattle[0] = [Cattle new];
    12      
    13     bullClass = NSClassFromString(BULL_CLASS);
    14     //即cattle[1],cattle[2]都是Bull类的实例
    15     cattle[1] = [bullClass new];
    16     cattle[2] = [bullClass new];
    17      
    18     say = @selector(saySomething);
    19     skin = NSSelectorFromString(SET_SKIN_COLOR);
    20 }
    21  
    22  
    23 //初始化id
    24 - (void) doWithCattleId:(id) aCattle colorParam:(NSString*) color
    25 {
    26     //第一次运行的时候
    27     if(notFirstRun == NO)
    28     {
    29         NSString *myName = NSStringFromSelector(_cmd);//取得当前正在执行的方法的名字
    30         NSLog(@"Running in the method of %@", myName);
    31         notFirstRun = YES;//修改初次运行标志位
    32     }
    33      
    34     NSString *cattleParamClassName = [aCattle className];//取得aCattle的"类名称"
    35      
    36     //如果aCattle是Bull或Cattle类的实例
    37     if([cattleParamClassName isEqualToString:BULL_CLASS] || [cattleParamClassName isEqualToString:CATTLE_CLASS])
    38     {
    39         [aCattle setLegsCount:4];//设置牛的4条腿
    40         if([aCattle respondsToSelector:skin])//如果aCattle对应的是类中,有定义方法"setSkinColor"
    41         {
    42             [aCattle performSelector:skin withObject:color];//则调用setSkinColor方法
    43         }
    44         else
    45         {
    46             NSLog(@"Hi, I am a %@, have not setSkinColor!", cattleParamClassName);//否则输出相应的提示信息
    47         }
    48         [aCattle performSelector:say];//最后执行saySomething方法(这二个方法在Bull与Cattle类中都有,所以肯定能运行)
    49     }
    50     else //如果aCattle即不是Bull类也不是Cattle类的实例
    51     {
    52         NSString *yourClassName = [aCattle className];
    53         NSLog(@"Hi, you are a %@, but I like cattle or bull!", yourClassName);//显示这个"异类"的相关信息
    54     }
    55 }
    56  
    57 //初始化选择器以及相应函数
    58 - (void) SELFuncs
    59 {
    60     [self doWithCattleId:cattle[0] colorParam:@"brown"];
    61     [self doWithCattleId:cattle[1] colorParam:@"red"];
    62     [self doWithCattleId:cattle[2] colorParam:@"black"];
    63     [self doWithCattleId:self colorParam:@"haha"];//这里故意传入一个异类self(即DoProxy本身),DoProxy当然不是Bull或Cattle
    64 }
    65  
    66 //函数指针测试
    67 - (void) functionPointers
    68 {
    69     //取得函数指针的第一种方式
    70     setSkinColor_Func=(void (*)(idSELNSString*)) [cattle[1] methodForSelector:skin];
    71     //上面的语句其实等效于下面这种方法
    72     //IMP setSkinColor_Func = [cattle[1] methodForSelector:skin];
    73      
    74     //用第二种方法取得saySomething的函数指针
    75     say_Func = [cattle[1] methodForSelector:say];
    76      
    77     //用函数指针的形式调用setSkinColor
    78     setSkinColor_Func(cattle[1],skin,@"verbose");
    79      
    80     NSLog(@"Running as a function pointer will be more efficiency!");
    81      
    82     //调用saySomething方法
    83     say_Func(cattle[1],say);
    84 }
    85  
    86 @end
    测试主函数main()
    01 #import <Foundation/Foundation.h>
    02 #import "DoProxy.h"
    03  
    04 int main (int argc, const char * argv[]) {
    05     NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    06     DoProxy *doProxy = [DoProxy new];
    07      
    08     [doProxy setAllIVars];
    09     [doProxy SELFuncs];
    10     [doProxy functionPointers];
    11      
    12     [doProxy release];
    13     [pool drain];
    14     return 0;
    15 }

    运行结果:

    2011-02-28 21:40:33.240 HelloSelector[630:a0f] Running in the method of doWithCattleId:colorParam:
    2011-02-28 21:40:33.245 HelloSelector[630:a0f] Hi, I am a Cattle, have not setSkinColor!
    2011-02-28 21:40:33.247 HelloSelector[630:a0f] Hello, I am a cattle, I have 4 legs.
    2011-02-28 21:40:33.248 HelloSelector[630:a0f] Hello, I am a red bull, I have 4 legs.
    2011-02-28 21:40:33.250 HelloSelector[630:a0f] Hello, I am a black bull, I have 4 legs.
    2011-02-28 21:40:33.251 HelloSelector[630:a0f] Hi, you are a DoProxy, but I like cattle or bull!
    2011-02-28 21:40:33.252 HelloSelector[630:a0f] Running as a function pointer will be more efficiency!
    2011-02-28 21:40:33.254 HelloSelector[630:a0f] Hello, I am a verbose bull, I have 4 legs.

  • 相关阅读:
    android 保存图片,及将图片更新到图库
    android 点击数字跳转到电话界面
    使用Picasso将加载的图片变成圆形
    如何获取listview里面的edittext或者RadioGroup的值,涉及到引发的混乱现象
    返回页面,并将此页面数据刷新一遍
    DrawerLayout建立侧滑时,显示侧滑页面,底层页面仍可以有点击响应,解决办法。
    实现双击退出程序
    sql语句查找某一列的值得最大值。
    vue 实战笔记一项目准备
    node的基础知识
  • 原文地址:https://www.cnblogs.com/xingchen/p/2102697.html
Copyright © 2011-2022 走看看