详解Objective-C获取消息工作机制

移动开发 iOS
本文介绍的是Objective-C如何获取消息工作机制,很详细的介绍了如何获取消息的过程,我们来看详细内容。

Objective-C获取消息工作机制是本文要介绍的内容,看name mangling的时候,也讲到了Objective-C的name mangling,于是又重新读了一下Objective-C 2.0 programming Language以及Objective-C 2.0 Runtime Reference里的相关内容,自己归纳一下。

先贴一段代码:

  1.    MyClass.h  
  2.    @interface MyClass : NSObject  
  3.    {  
  4.     }  
  5.    @end  
  6.    MyClass.m  
  7.    #import </usr/include/objc/runtime.h> 
  8.    #import “MyClass.h”  
  9.    void myClassIMP(id _rec, SEL _cmd, int theInt)  
  10.    {  
  11.       NSLog(@”dynamic added method:%d”,theInt);  
  12.    }  
  13.    
  14. - (id)init  
  15. {  
  16.     if( ( self = [super init]) != nil )  
  17.     {  
  18.    class_addMethod([MyClass class], @selector(dynGeneratedMethod:),(IMP)myClassIMP,”v@:i”);  
  19.      }  
  20.     return self;  
  21. }  
  22.  
  23. Main.c  
  24. #import “MyClass.h”  
  25. int main(int argc, char *argv[])  
  26. {  
  27.   MyClass theInstance = [[MyClass alloc] init];  
  28.   [theInstance dynGeneratedMethod:10];  
  29.  return 0;  

这段代码执行的结果是在控制台上输出:

  1. dynamic added method:10 

接着来详细分析一下上面的代码:

在ObjC的类中这样的一个声明 – (void)foo:(int)a;被称作方法(method),而在调用的地方: [theClass foo:10];则被称之为发送消息(send message),具体来说是给对象theClass 发送foo:消息,注意这里foo后面的”:”,它也是消息名称的一部分,最前面的'-'代表实例方法,'+'代表类方法。而类似的语句,在C或C++中,通常被称为呼叫函数(call function),在ObjC中,函数(function)一词很少用到,不是它不存在,而是它被ObjC runtime给隐藏了起来。
  
如前所述,ObjC是以消息机制来工作的,但其实诸如-(void)foo:(int)a的语句在编译时被objc_msgSend(receiver,selector,arg1,arg2,….)替换了,所以其实每一条发送消息的代码本质上还是调用函数(call function),不过他们调用的都是同一个函数objc_msgSend(也可能是objc_msgSend_stret(返回值是结构体),objc_msgSend_fpret(返回值是浮点型)等)

分析objc_msgSend的参数,第一个receiver的类型是id,代表接受消息的对象,第二个是selector代表接收对象的方法,后面的是该方法的参数,之前那条语句的被编译器替换后就是:

  1. [theClass foo:10]  -> objc_msg(theClass,@selector(foo:),10); 

因为消息的接受对象和接受对象的方法都参数化,所以在运行时刻,接受对象和接受对象的方法都可以是动态的!

比如说程序里面可以这样写:

  1. id helper = getTheReceiver();  
  2. SEL request = getTheSelector();  
  3. [helper performSelector:request]; 

它的实现是基于ObjC runtime. NSObject类实现了这套机制,所以每一个继承于NSObject的类都能自动获得runtime的支持。在这样的一个类中,有一个isa指针,指向该类定义的数据结构体,这个结构体是由编译器编译时为类(须继承于NSObject)创建的.在这个结构体中有包括了指向其父类类定义的指针以及Dispatch table. Dispatch table是一张SEL和IMP的对应表。

对于名称相同的方法,他们都有相同的SEL,方法的名称不包括类名称,所以子类和父类中的同名方法拥有相同的SEL,但是他们的实现可以各不相同,因而在他们各自的Dispatch表中SEL所对应的IMP是不同的,IMP是一个函数指针,而虽然每一个SEL对应的是一个方法的名称,但考虑到效率,SEL本身是一个整型,编译器会另外生成一张SEL和方法名称对应的表。有了这样的结构,objc就可以实现多态了。还是这行代码:

  1. [theClass foo:10]; 

是向theClass发送了foo:消息,那么首先在theClass的类结构的Dispatch table里找有没有对应的SEL,如果有的话,就表示theClass有响应该消息的方法,程序就跳到该方法的代码地址头(由IMP指定),开始执行。如果在theClass的Dispatch table找不到对应的SEL,那么就会通过isa所指的结构体中包含的父类指针,到父类里面去寻找,如果到最后还是没有找到,就会出现runtime error.所以说,即使theClass以及它的父类都没有定义-(void) foo:(int)a方法,程序还是可以通过编译,但如果是用xcode的话,编译器会有警告,告知theClass可能无法响应该消息。不会报错的原因是类的方法也可以在执行时刻创建!上面的代码:

  1. class_addMethod([MyClass class], @selector(dynGeneratedMethod:),(IMP)myClassIMP,”v@:i”); 

就是给MyClass类在执行时刻增加了一个响应dynGeneratedMethod:消息的方法,这样之后对任何MyClass的instance类发送dynGeneratedMethod:消息,就会得到响应了.myClassIMP是类收到该消息时要调用的方法,其声明如下:

  1. void myClassIMP(id _rec, SEL _cmd, int theInt) 

这个方法的前面两个参数是必须的,之后的参数才是我们实际用到的参数,数目和@selector()中的冒号数一样,冒号数代表的就是参数个数。第一个参数是消息的接受对象,是MyClass的实例,第二个参数是由SEL代表的具体消息。

 Class_addMethod的最后一个参数是表示dynGeneratedMethod:的返回值和参数信息,不过我自己试了一下,这个参数不起作用。

几个要点:

1、对于C中被称为函数(function)和函数调用(function call)的地方,在ObjC中被叫做方法(method)和发送消息(send message).试图调用未定义的方法会导致编译错误,而发送一条消息,即使没有任何类定义了响应该消息的方法,编译时也不会报错,从语义上讲这也是对的,发一条消息本来就不要求一定有人会响应,不过如果执行到发送消息的代码时真的没有类可以响应的话,是会发生runtime error,为了避免这种事情发生,可以先进行检测,这样写:

  1. if( [myClass respondsToSelector:@selector(foo:)])  
  2. {  
  3.    [myClass foo:10];  

我感觉ObjC这样的一套sender receiver的定义更注重面向对象的概念。类是一个接收者(receiver),如果定义了某个方法,就可以接收和这个方法名称相同的消息。而使用该类的client(sender),则尝试向该类发送消息.如果匹配了,就跳到类的方法里执行。

2、方法名称是诸如foo:,不包括返回类型,参数类型,而又因为一个foo:对应于一个SEL,所以说ObjC不支持相同的foo:有不同的返回类型,也不支持重载。不过类方法和实例方法可以有相同的名字,而又有不同类型的参数和返回类型,因为它们不是处在同一张dispatch table中。

3、不仅类的方法可以运行时刻创建,类本身也可以在运行时刻创建,前面提到继承于NSObject的类,编译器会帮忙生成ObjC runtime所需要的类结构定义,只要我们在代码里也按照那个结构创建了自己的类,那一样可以获得ObjC runtime的支持。 

小结:详解Objective-C获取消息工作机制的内容介绍完了,从Objective-C消息机制可以看出,它是一门很灵活的语言。最后希望本文对你有所帮助!

责任编辑:zhaolei 来源: 互联网
相关推荐

2011-08-17 10:58:59

Objective-C构造函数

2011-07-29 16:16:30

Objective-c block

2011-08-17 10:29:39

Objective-C预处理

2011-08-18 13:28:35

Objective-C内存

2015-10-08 10:01:10

Objective-CLayout

2011-07-18 16:36:51

Objective-C XCode

2014-04-01 10:50:42

iOS开发runtimeObjective-C

2011-08-04 13:38:01

Objective-C C++

2011-08-16 10:23:04

Objective-CNSAutoreleaXcode常用键

2011-07-08 18:44:09

Objective-C Self Super

2011-08-16 13:43:40

Objective-C文件cocoa

2011-07-27 16:55:12

Objective-c 闭包

2011-08-01 17:11:43

Objective-C 函数

2011-08-15 14:32:42

Objective-C委托协议

2014-04-28 09:56:56

Objective-CiOS命名空间

2011-08-17 11:05:22

Objective-C方法

2011-07-29 15:47:21

iPhone开发 Objective- C

2013-03-27 12:54:00

iOS开发Objective-C

2011-05-11 11:20:26

Objective-C

2011-05-11 15:58:34

Objective-C
点赞
收藏

51CTO技术栈公众号