- 浏览: 13748371 次
- 性别:
- 来自: 洛杉矶
文章分类
- 全部博客 (1994)
- Php / Pear / Mysql / Node.js (378)
- Javascript /Jquery / Bootstrap / Web (435)
- Phone / IOS / Objective-C / Swift (137)
- Ubuntu / Mac / Github / Aptana / Nginx / Shell / Linux (335)
- Perl / Koha / Ruby / Markdown (8)
- Java / Jsp (12)
- Python 2 / Wxpython (25)
- Codeigniter / CakePHP (32)
- Div / Css / XML / HTML5 (179)
- WP / Joomla! / Magento / Shopify / Drupal / Moodle / Zimbra (275)
- Apache / VPN / Software (31)
- AS3.0/2.0 / Flex / Flash (45)
- Smarty (6)
- SEO (24)
- Google / Facebook / Pinterest / SNS (80)
- Tools (22)
最新评论
-
1455975567:
xuezhongyu01 写道wocan23 写道我想问下那个 ...
Mysql: LBS实现查找附近的人 (两经纬度之间的距离) -
xuezhongyu01:
wocan23 写道我想问下那个111.1是怎么得来的我也看不 ...
Mysql: LBS实现查找附近的人 (两经纬度之间的距离) -
18335864773:
试试 pageoffice 在线打开 PDF 文件吧. pag ...
jquery在线预览PDF文件,打开PDF文件 -
青春依旧:
opacity: 0.5; 个人喜欢这种方式!关于其他css特 ...
css透明度的设置 (兼容所有浏览器) -
July01:
推荐用StratoIO打印控件,浏览器和系统的兼容性都很好,而 ...
搞定网页打印自动分页问题
Objective-C 2.0 with Cocoa Foundation--- 5,Class类型,选择器Selector以及函数指针
5,Class类型,选择器Selector以及指针函数
系列讲座有着很强的前后相关性,如果你是第一次阅读本篇文章,为了更好的理解本章内容,笔者建议你最好从本系列讲座的第1章开始阅读,请点击这里 。
上一章笔者介绍了在Objective-C里面继承的概念。有了继承的知识我们可以重复的使用很多以前生效的代码,这样就大大的提高了代码开发的效率。在本章,笔者要向同学们介绍几个非常重要的概念,Class类型, 选择器Selector以及指针函数。
我们在实际上的编程过程中,也许会遇到这样的场景,那就是我们在写程序的时候不能确切的知道我们需要使用什么类,使用这个类的什么方法。在这个时 候,我们需要在我们的程序里面动态的根据用户的输入来创建我们在写程序不知道的类的对象,并且调用这个对象的实例方法。Objective-C为我们提供 了Class类型, 选择器Selector以及指针函数来实现这样的需求,从而大大的提高了我们程序的动态性能。
在Objective-C里面,一个类被正确的编译过后,在这个编译成功的类里面,存在一个变量用于保存这个类的信息。我们可以通过一个普通的字符 串取得这个Class,也可以通过我们生成的对象取得这个Class。Class被成功取得之后,我们可以把这个Class当作一个已经定义好的类来使用 它。
Selector和Class比较类似,不同的地方是Selector用于表示方法。 在Objective-C的程序进行编译的时候,会根据方法的名字(包括参数列表)确定一个唯一的身份证明(实际上就是一个整数),不用的类里面的相同名 字相同声明的方法的身份证明是一样的。这样在程序执行的时候,runtime就不用费力的进行方法的名字比较来确定是执行哪一个方法了,只是通过一个整数 的寻找就可以马上定位到相应的方法,然后找到相应的方法的入口地址,这样方法就可以被执行了。
笔者在前面的章节里面叙述过,在Objective-C里面消息也就是方法的执行比C语言的直接找到函数入口地址执行的方式,从效率上来讲是比较低 下的。尽管Objective-C使用了Selector等招数来提高寻找效率,但是无论如何寻找的过程,都是要消耗一定的时间的。好在 Objective-C是完全兼容C的,它也有指针函数的概念。当我们需要执行效率的时候,比如说在一个很大的循环当中需要执行某个功能的时候,我们可以 放弃向对某一个对象发送消息的手段,用指针函数取而代之,这样就可以获得和C语言一样的执行效率了。
说到这里,可能有的同学已经有些茫然了。这些概念有些令人难以理解,但是它们确实是Objective-C的核心的功能。掌握了这些核心的功能之 后,同学们可以很轻松的看懂苹果的SDK里面的很多东西含义,甚至可以自己动手写一些苹果没有为我们提供的功能。所以建议大家仔细研读本章的内容,如果有 什么问题,可以发个帖子大家可以共同探讨。
从笔者的观点上来看,对于有Java或者C++或者其他面向对象的语言的经验的同学来说,前面的从第1到第4章的内容也许有些平淡无奇。从第5章开 始,我们将要逐渐的深入到Objective-C的核心部分。笔者的最终目的,虽然是向大家介绍iPhone开发的入门,但是笔者认为了解了 Objective-C的基本概念以及使用方法之后,熟悉iPhone的应用程序的开发将是一件水到渠成的轻松的事情。否则如果你直接就深入到 iPhone的开发的话,在绝大多数时间你也许因为一个小小的问题就会困扰你几个小时甚至几天,解决这些问题的唯一方法就是熟悉Objective-C和 Cocoa Foundation的特性。
好了,说了很多我们从下面就要开始,我们的手法和前面几章是一样的,我们首先要介绍一下本章程序的执行结果。
5.1,本章程序的执行结果
图5-1,第5章程序的执行结果
在本章里面,我们将要继续使用我们在前面几章已经构筑好的类Cattle和Bull。为了灵活的使用Cattle和Bull,我们将要构筑一个新的 类,DoProxy。在DoProxy里面,我们将会引入几个我们的新朋友,他们分别是BOOL,SEL,IMP,CLASS。通过这些新的朋友我们可以 动态的通过设定文件取得Cattle和Bull的类,还有方法以及方法指针。下面将要介绍如何构筑本章程序。同学们可以按照本章所述的步骤来构筑,也可以 通过从这里 下载。不过为了熟悉代码的写作,笔者强烈建议大家按照笔者所述的步骤来操作。
5.2,实现步骤
第一步,按照我们在第2章所述的方法,新建一个项目,项目的名字叫做05-Hello Selector。如果你是第一次看本篇文章,请到这里 参看第二章的内容。
第二步,按照我们在第4章的4.2节的第二,三,四步所述的方法,把在第4章已经使用过的“Cattle.h”,“Cattle.m”,“Bull.h”还有“Bull.m” 导入本章的项目里面。如果你没有第4章的代码,请到这里 下载。如果你没有阅读第4章的内容,请参看这里 。
第三步,把鼠标移动到项目浏览器上面的“Source”上面,然后在弹出的菜单上面选择“Add”,然后在子菜单里面选择“New Files”,然后在新建文件对话框的左侧选择“Cocoa Touch Classes”,然后在右侧窗口选择“NSObject subclass”,选择“Next”,在“New File”对话框里面的“File Name”栏内输入“DoProxy.m”。在这里笔者没有给出图例,在这里新建文件的步骤和第3章的第二步到第四步相同,只是文件名字不一样。第一次看 到本篇 文章的同学可以参照第3章。
第四步,打开“DoProxy.h”做出如下修改并且保存
#import <Foundation/Foundation.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
第五步,打开“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
第六步,打开“05-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; }
第七步,选择屏幕上方菜单里面的“Run”,然后选择“Console”,打开了Console对话框之后,选择对话框上部中央的“Build and Go”,如果不出什么意外的话,那么应该出现入图5-1所示的结果。如果出现了什么意外导致错误的话,那么请仔细检查一下你的代码。如果经过仔细检查发现 还是不能执行的话,可以到这里 下载笔者为同学们准备的代码。 如果笔者的代码还是不能执行的话,请告知笔者。
5.3,BOOL类型
我们现在打开“DoProxy.h”文件。“DoProxy.h”文件的第3行到第5行是三个预定义的三个字符串的宏。我们将在程序当中使用这3个宏,为 了实现代码的独立性,在实际的程序开发当中,我们也许考虑使用一个配置的文本文件或者一个XML来替代这些宏。但是现在由于笔者的主要目的是讲解 Objective-C的概念,为了避免较多的代码给大家带来理解主题的困难,所以笔者没有使用配置文件或者XML来表述这些可以设定的常量。
“DoProxy.h”的第7行对同学们来说也是老朋友了,是通知编译器,我们需要声明一个DoProxy类,从NSObject继承。
我们在第8行遇到了我们的一个新的朋友,BOOL:
我们定义了一个notFirstRun的实例变量,这个变量是布尔类型的。我们的实例方法doWithCattleId需要被执行多次,我们在第一 次执行doWithCattleId的时候需要向控制输出包含doWithCattleId的方法名字的字符串,关于这个字符串的内容,请参考图5-1。
好的,我们现在需要看看在Objective-C里面BOOL是怎样定义的,我们把鼠标移动到BOOL上面,然后单击鼠标右键选择弹出菜单的“Jump to Definition”,然后Xcode会打开objc.h文件,我们看到下面的代码:
typedef signed char BOOL; // BOOL is explicitly signed so @encode(BOOL) == "c" rather than "C" // even if -funsigned-char is used. #define OBJC_BOOL_DEFINED #define YES (BOOL)1 #define NO (BOOL)0
我们看到这段代码,我们可以这样理解,在Objective-C里面,BOOL其实是signed char,YES是1,NO是0。我们可以这样给BOOL赋值:
BOOL x = YES; BOOL y = NO;
关于BOOL,实际上就是一个开关的变量,但是我们需要注意下面2点:
第一点,从本质上来说BOOL是一个8bit的一个char,所以我们在把其他比如说short或者int转换成为BOOL的时候一定要注意。如果 short或者int的最低的8位bit都是0的话,尽管除了最低的8位以外都不是0,那么经过转换之后,就变成了0也就是NO。比如说我们有一个int 的值是0X1000,经过BOOL转换之后就变成了NO。
第二点,Objective-C里面的所有的逻辑判断例如if语句等等和C语言保持兼容,如果数值不是0判断为真,如果数值是0那么就判断为假,并不是说定义了BOOL值之后就变成了只有1或者YES为真。所以下面的代码的判断都为真:
if ( 2 )
if ( - 1 )
5.4,SEL类型
让我们接着看“DoProxy.h”文件的下列代码:
id cattle[3]; SEL say; SEL skin;
其中id cattle[3]定义了一个数组用于存储Cattle或者Bull对象。这一行代码估计大家都很熟悉,笔者就不赘述了。像这样的传统的数组并不能完全满 足我们的需求,当我们需要做诸如追加,删除等操作的时候,会很不方便。在随后的章节里面笔者将要向大家介绍传统数组的替代解决方案NSArray。
上一段代码的第二行和第三行是本节所关注的,就是SEL类型。Objective-C在编译的时候,会根据方法的名字(包括参数序列),生成一个用 来区分这个方法的唯一的一个ID,这个ID就是SEL类型的。我们需要注意的是,只要方法的名字(包括参数序列)相同,那么它们的ID都是相同的。就是 说,不管是超类还是子类,不管是有没有超类和子类的关系,只要名字相同那么ID就是一样的。除了函数名字和ID,编译器当然还要把方法编译成为机器可以执 行的代码,这样,在一个编译好的类里面,就产生了如下图所示方法的表格示意图(本构造属于笔者推测,没有得到官方证实,所以图5-2为示意图仅供参考,我 们可以暂时认为是这样的)。
图5-2,方法的表格示意图
请注意setSkinColor后面有一个冒号,因为它是带参数的。由于存在这样的一个表格,所以在程序执行的时候,我们可以方便的通过方法的名字,获取到方法的ID也就是我们所说的SEL,反之亦然。具体的使用方法如下:
SEL 变量名 = @selector(方法名字); SEL 变量名 = NSSelectorFromString(方法名字的字符串); NSString *变量名 = NSStringFromSelector(SEL参数);
其中第1行是直接在程序里面写上方法的名字,第2行是写上方法名字的字符串,第3行是通过SEL变量获得方法的名字。我们得到了SEL变量之后,可以通过下面的调用来给一个对象发送消息:
这样的机制大大的增加了我们的程序的灵活性,我们可以通过给一个方法传递SEL参数,让这个方法动态的执行某一个方法;我们也可以通过配置文件指定需要执行的方法,程序读取配置文件之后把方法的字符串翻译成为SEL变量然后给相应的对象发送这个消息。
从效率的角度上来说,执行的时候不是通过方法名字而是方法ID也就是一个整数来查找方法,由于整数的查找和匹配比字符串要快得多,所以这样可以在某种程度上提高执行的效率。
5.5,函数指针
在讲解函数指针之前,我们先参看一下图5-2,函数指针的数值实际上就是图5-2里面的地址,有人把这个地址成为函数的入口地址。在图5-2里面我 们可以通过方法名字取得方法的ID,同样我们也可以通过方法ID也就是SEL取得函数指针,从而在程序里面直接获得方法的执行地址。或者函数指针的方法有 2种,第一种是传统的C语言方式,请参看“DoProxy.h” 的下列代码片断:
void(*setSkinColor_Func) (id, SEL, NSString*); IMP say_Func;
其中第1行我们定义了一个C语言里面的函数指针,关于C语言里面的函数指针的定义以及使用方法,请参考C语言的书籍和参考资料。在第一行当中,值得我们注意的是这个函数指针的参数序列:
第一个参数是id类型的,就是消息的接受对象,在执行的时候这个id实际上就是self,因为我们将要向某个对象发送消息。
第二个参数是SEL,也是方法的ID。有的时候在消息发送的时候,我们需要使用用_cmd来获取方法自己的SEL,也就是说,方法的定义体里面,我们可以通过访问_cmd得到这个方法自己的SEL。
第三个参数是NSString*类型的,我们用它来传递skin color。在Objective-C的函数指针里面,只有第一个id和第二个SEL是必需的,后面的参数有还是没有,如果有那么有多少个要取决于方法的声明。
现在我们来介绍一下Objective-C里面取得函数指针的新的定义方法,IMP。
上面的代码的第一行比较复杂,令人难以理解,Objective-C为我们定义了一个新的数据类型就是在上面第二行代码里面出现的IMP。我们把鼠标移动到IMP上,单击右键之后就可以看到IMP的定义,IMP的定义如下:
这个格式正好和我们在第一行代码里面的函数指针的定义是一样的。
我们取得了函数指针之后,也就意味着我们取得了执行的时候的这段方法的代码的入口,这样我们就可以像普通的C语言函数调用一样使用这个函数指针。当然我们 可以把函数指针作为参数传递到其他的方法,或者实例变量里面,从而获得极大的动态性。我们获得了动态性,但是付出的代价就是编译器不知道我们要执行哪一个 方法所以在编译的时候不会替我们找出错误,我们只有执行的时候才知道,我们写的函数指针是否是正确的。所以,在使用函数指针的时候要非常准确地把握能够出 现的所有可能,并且做出预防。尤其是当你在写一个供他人调用的接口API的时候,这一点非常重要。
5.6,Class类型
到目前为止,我们已经知道了对应于方法的SEL数据类型,和SEL同样在Objective-C里面我们不仅仅可以使用对应于方法的SEL,对于类在 Objective-C也为我们准备了类似的机制,Class类型。当一个类被正确的编译过后,在这个编译成功的类里面,存在一个变量用于保存这个类的信 息。我们可以通过一个普通的字符串取得 这个Class,也可以通过我们生成的对象取得这个Class。Class被成功取得之后,我们可以把这个Class当作一个已经定义好的类来使用它。这 样的机制允许我们在程序执行的过程当中,可以Class来得到对象的类,也可以在程序执行的阶段动态的生成一个在编译阶段无法确定的一个对象。
因为Class里面保存了一个类的所有信息,当然,我们也可以取得一个类的超类。关于Class类型,具体的使用格式如下:
Class 变量名 = [类或者对象 class]; Class 变量名 = [类或者对象 superclass]; Class 变量名 = NSClassFromString(方法名字的字符串); NSString *变量名 = NSStringFromClass(Class参数);
第一行代码,是通过向一个类或者对象发送class消息来获得这个类或者对象的Class变量。
第二行代码,是通过向一个类或者对象发送superclass消息来获得这个类或者对象的超类的Class变量。
第三行代码,是通过调用NSClassFromString 函数,并且把一个字符串作为参数来取得Class变量。这个在我们使用配置文件决定执行的时候的类的时候,NSClassFromString给我们带来了极大的方便。
第四行代码,是NSClassFromString 的反向函数NSStringFromClass ,通过一个Class类型作为变量取得一个类的名字。
当我们在程序里面通过使用上面的第一,二或者第三行代码成功的取得一个Class类型的变量,比如说我们把这个变量名字命名为myClass,那么 我们在以后的代码种可以把myClass当作一个我们已经定义好的类来使用,当然我们可以把这个变量作为参数传递到其他的方法当中让其他的方法动态的生成 我们需要的对象。
5.7,DoProxy.h里面的方法定义
DoProxy.h里面还有一些实例方法,关于方法的定义的格式,同学们可以参照第三章。我们现在要对DoProxy.h里面定义的方法的做一下简要的说明。
- (void) doWithCattleId:(id) aCattle colorParam:(NSString*) color; - (void) setAllIVars; - (void) SELFuncs; - (void) functionPointers;
第一行的方法,是设定aCattle,也就是Cattle或者Bull对象的属性,然后调用saySomething方法,实现控制台的打印输出。
第二行的方法,是把我们定义的DoProxy类里面的一些变量进行赋值。
第三行的方法,是调用doWithCattleId方法。
第四行的方法,是调用了函数指针的方法。
好的,我们把DoProxy.h的内容介绍完了,让我们打开DoProxy.m。
5.8,DoProxy.m的代码说明
有了DoProxy.h的说明,同学们理解DoProxy.m将是一件非常轻松的事情,让我们坚持一下把这个轻松的事情搞定。由于篇幅所限,笔者在这里的讲解将会省略掉非本章的内容。
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
第10行代码是通过一个预定义的宏BULL_CLASS 取得Bull的Class变量。
第11和12行代码是使用bullClass来初始化我们的cattle实例变量数组的第2和第3个元素。
第14行是通过@selector 函数来取得saySomething 的SEL变量。
第15行是通过向NSSelectorFromString传递预定义的宏SET_SKIN_COLOR来取得setSkinColor的SEL变量。
第22行,笔者打算“戏弄”一下doWithCattleId ,向传递了不合适的参数。
第26行,笔者取得了传统的C语言的函数指针,也是使用了第5.5节所述的第一种取得的方法。
第28行,笔者通过5.5节所述的第二种取得的方法得到了函数指针say_Func 。
第29行和31行分别执行了分别在第26行和28行取得的函数指针。
第35行是一个BOOL型的实例变量notFirstRun 。当对象被初始化之后,确省的值是NO。第一次执行完毕之后,我们把这个变量设定成为YES,这样就保证了花括号里面的代码只被执行一次。
第37行我们通过_cmd 取得了doWithCattleId 这个方法名字用于输出。当然同学们在设计方法的提供给别人使用的时候,为了防止使用方法的人把这个方法本身传递进来造成死循环,需要使用_cmd这个系统隐藏的变量判断一下。笔者在这里没有做出判断,这样写从理论上来说存在一定的风险。
第42行,我们通过向对象发送className 消息来取得这个对象的类的名字。
第43行和第44行,我们通过NSString的方法isEqualToString 来判断取得的类的名字是否在我们事先想象的范围之内,我们只希望接受Bull或者Cattle类的对象。
第46行,本来我们想通过SEL的方式来进行这个牛股的设定,但是由于它的参数不是从NSObject继承下来的,所以我们无法使用。我们会有办法解决这个问题的,我们将在后面的章节里面介绍解决这个问题的方法。
第47行的代码,有一个非常重要NSObject的方法respondsToSelector ,通过向对象发送这个消息,加上一个SEL,我们可以知道这个对象是否可以相应这个SEL消息。由于我们的Cattle无法相应setSkinColor消息,所以如果对象是Cattle类生成的话,if语句就是NO所以花括号里面的内容不会得到执行。
第59行,我们通过类的名字发现了一个假冒的Cattle,我们把这个假冒的家伙给揪出来,然后实现了屏幕打印。
5.9,本章总结
本章给同学们介绍了几个新的数据类型,以及使用方法,这些数据类型分别是BOOL,SEL,Class,IMP。
本章的内容很重要,希望同学们花一点时间仔细的理解一下。应该说,本章的内容有些令人难以理解,或者说知道了SEL,Class,IMP之后也许不 知道如何使用,遇到什么情况的时候需要使用。不过在学习Objective-C的初级阶段,不知道这些也没有关系,但是SEL,Class,IMP的概念 需要掌握,否则当你遇到别人写的质量比较高的代码或者苹果官方的技术文档的时候,你会觉得理解起来比较吃力。
本章内容也是理解下一章内容的基础,下一章我们将要讲述NSObject的奥秘。
谢谢大家!
来源:http://www.cnblogs.com/yaski/archive/2009/04/05/1429735.html
ps:
SEL和IMP的用法
SEL是“selector”的一个类型,表示一个方法的名字。@selector是一个选择器,里面的参数是一个方法,返回的是SEL类型,也就是方法的名字。
IMP定义为 id (*IMP) (id, SEL, …)。这样说来, IMP是一个指向函数的指针,这个被指向的函数包括id(“self”指针),调用的SEL(方法名),再加上一些其他参数。说白了IMP就是实现方法。
下面是如何使用的示例:
- (void)methodWithInt:(int)firstInt andInt:(int)secondInt { NSLog(@"%d", firstInt + secondInt); }
SEL theSelector = @selector(methodWithInt:andInt:); IMP theImplementation = [self methodForSelector:theSelector];
其中,methodForSelector是NSObject中的方法,返回参数中指定的方法的入口地址,说白了,就是函数指针。
setSkinColor_Func=(void (*)(id, SEL, NSString*)) [cattle[1]
methodForSelector:skin]; //强制转化为setSkinColor_Fun定义的void (*)(id, SEL,
NSString*)类型指针
这们可以将这里的cattle[1]实例变量换成一个拥有-setSkinColor:(int) intVar签名的方法来试一下,这里并不强制转化为etSkinColor_Fun定义的函数类型指针
IMP impVar =[someclass methodForSelector:skin];
然后我们求出comeclass下-setSkinColor:(int) intVar方法的地址,看看impVar的地址是否与someclass下的-setSkinColor:(int) intVar方法的地址是相同的
- 05-Hello_Selector.zip (48.5 KB)
- 下载次数: 1
发表评论
-
手机firebug查看网页代码 How to View Website Source Codes on iPad / iPhone
2016-04-26 02:41 1173You’re using your iPad to br ... -
Android模拟器genymotion的安装和使用
2016-03-18 01:16 2534Genymotion概述 Genymotion是一套完整的 ... -
编码之道:取个好名字很重要
2015-10-14 05:19 1178代码就是程序员的孩子,给“孩子”取个好听的名字很重 ... -
Genymotion - 强大好用高性能的 Android 模拟器 (在电脑流畅运行APK安卓软件游戏的利器)
2015-06-05 13:34 7398随着 Android 系统的应用和游戏越来越丰富,甚至有 ... -
收集几个移动平台浏览器的User-Agent
2014-07-23 02:33 3034List of all Mobile Browsers ... -
常用浏览器修改User-Agent的方法
2014-06-28 02:58 10993之前有介绍收集的几个移动平台浏览器的User-Agent,以 ... -
更简洁的方式修改Chrome的User Agent,轻松体验移动版网络
2014-06-28 02:53 6952国庆节在家宅着,使用3g上网卡上网,和在公司上网不一样的是 ... -
3个检测浏览器User-Agent信息的网站
2014-06-28 02:52 2565刚刚在收集各个移动平台浏览器的User-Agent(参见这 ... -
根据移动设备屏幕像素密度,给予不同分辨率的图片
2014-06-26 00:52 2976在出现iphone4之前的相当长的时间内,网站开发人员 ... -
视网膜New iPad与普通分辨率iPad页面的兼容处理
2014-06-26 00:44 1352一、这是篇经验分享 ... -
iOS8开发-Swift编程
2014-06-25 00:45 1916课时列表 章节1:第一个Swift应用 ... -
Swift中文教程(二十三) 高级运算符
2014-06-25 00:43 831除了基本操作符中所讲的运算符,Swift还有许多复杂的高级 ... -
Swift中文教程(二十二) 泛型
2014-06-25 00:35 1076泛型代码可以让你写出根据自我需求定义、适用于任何类型的,灵 ... -
Swift中文教程(二十一) 协议
2014-06-24 05:25 1465Protocol(协议)用于统一方法和属性的名称,而不实现任 ... -
Swift中文教程(二十) 扩展
2014-06-24 00:47 739扩展就是向一个已有的类、结构体或枚举类型添加新功能(fun ... -
Swift中文教程(十九) 类型嵌套
2014-06-24 00:44 935枚举类型常被用于实现特定类或结构体的功能。也能够在有多种变量 ... -
Swift中文教程(十八) 类型检查
2014-06-24 00:41 782类型检查是一种检查类实例的方式,并且或者也是让实例作为它的 ... -
Swift中文教程(十七) 可选链
2014-06-17 05:11 909可选链(Optional Chaining)是一种可以请求 ... -
Swift中文教程(十六) 自动引用计数
2014-06-17 05:05 1295Swift使用自动引用计数(ARC)来管理应用程序的内存使 ... -
Swift中文教程(十五) 析构
2014-06-17 04:57 1041在一个类的实例被释放之前,析构函数会被调用。用关键字dei ...
相关推荐
#### 第 5 章:Class 类型、选择器 Selector 以及函数指针 Class 类型、选择器和函数指针是 Objective-C 中非常重要的概念。Class 类型允许你访问类的元信息,而选择器则是用于发送消息的标识符。函数指针则是一种...
Objective-C 2.0是Apple开发的面向对象的编程语言,它是Cocoa和Cocoa Touch框架的基础。在Objective-C中,类方法(Class Methods)和私有方法(Private Methods)是两个重要的概念,它们对于理解和编写高效、安全的...
本教程将深入探讨Objective-C 2.0与Cocoa Foundation的结合,从经典的"Hello, World!"程序开始,逐步揭示这门语言的强大之处。 "Hello, World!"是所有编程旅程的传统起点,它展示了语言的基本语法和输出功能。在...
本节将深入探讨Objective-C 2.0中的继承机制,以及如何在Cocoa Foundation框架下使用它。 ### 继承的概念 继承是面向对象编程的一个关键特性,允许一个类(子类或派生类)从另一个类(父类或基类)继承属性和行为。...
Objective-C 2.0是Apple开发的面向对象的编程语言,它是Cocoa和Cocoa Touch框架的基础。在Objective-C中,对象的初始化和实例变量的作用域是编程中的关键概念,对于理解和创建健壮的iOS和macOS应用程序至关重要。 ...
第一部分全面讲解了Objective-C语言的基础知识,包括类、对象、方法、数据类型、表达式、程序结构、继承、多态、动态类型和动态绑定、函数、数组、结构和指针等。这部分为读者打下了坚实的语言基础,适合编程初学者...
《Effective Objective-C 2.0》是一本由Matt Galloway所著的关于Objective-C编程语言的书籍,主要面向开发iOS和OS X应用程序的开发者。这本书详细阐述了如何利用Objective-C 2.0的新特性和最佳实践来提高程序的效率...
Objective-C 2.0 是苹果公司开发的一种面向对象的编程语言,它是基于C语言的,同时引入了Smalltalk的关键概念,如消息传递和动态类型。这个语言主要用于开发iOS和macOS平台的应用程序。《Objective-C 2.0 程序设计》...
- **数据类型与表达式**:Objective-C支持多种数据类型,包括基本类型(如int、float等)以及自定义类型。第四章将详细介绍这些数据类型以及如何在程序中使用它们构建复杂的表达式。 - **程序结构**:Objective-C...
- **和运行时系统的交互**:解释了Objective-C程序如何通过不同的方式与运行时系统进行通信,包括通过Objective-C源代码、通过`NSObject`类的方法以及直接调用运行时系统的函数。 - **消息**:深入探讨了消息发送...
### 关于Objective-C 2.0编程语言的关键知识点 #### 一、Objective-C 2.0简介 Objective-C 2.0 是一种通用的面向对象的编程语言,它结合了C语言的基础特性和Smalltalk的对象模型。Objective-C 2.0 由 Apple Inc. ...
Objective-C 2.0 是一种通用、面向对象的编程语言,它结合了C语言的基础特性和Smalltalk的对象模型及动态特性。Objective-C 2.0 由 Apple Inc. 开发并维护,广泛应用于开发 macOS 和 iOS 应用程序。 #### 二、...
2. **与运行时系统的交互**:探讨了Objective-C程序如何与运行时系统进行交互,包括通过Objective-C源代码、通过类`NSObject`的方法以及通过直接调用运行时系统的函数。 3. **消息**:详细解释了Objective-C中的...
### Objective-C 2.0 运行时系统编程指南知识点详解 #### 概述 Objective-C 2.0 的运行时系统是该语言的核心组成部分之一,它负责在程序执行过程中处理许多关键操作,如方法调用、类信息的管理、消息转发等。深入...
Objective-C 2.0中的属性提供了一种更简洁的方法来声明类的实例变量和访问器方法。这不仅使代码更加清晰易读,还允许编译器自动生成getter和setter方法,从而大大减少了样板代码的数量。 ##### 5. **分类...
C编程的电子书,可能涵盖了语言的基本语法、类和对象的概念、消息传递机制、内存管理(在Objective-C中是ARC,即自动引用计数)、类别、协议、 Blocks、GCD(Grand Central Dispatch)以及Cocoa或Cocoa Touch框架的...