您的位置:首页 > 其它

个人对objc_msgSend 函数具体实现过程解读

2015-05-05 18:32 267 查看


以前不太明白此函数具体实现过程,今天从相关资料总结出具体实现如下:

(一).认识类定义:


Class和Object基础数据结构


Class

objc/runtime.h中objc_class结构体的定义如下:
struct objc_class {

Class isa OBJC_ISA_AVAILABILITY; //isa指针指向Meta Class,因为Objc的类的本身也是一个Object,为了处理这个关系,runtime就创造了Meta Class,当给类发送[NSObject alloc]这样消息时,实际上是把这个消息发给了Class Object
#if !__OBJC2__
Class super_class OBJC2_UNAVAILABLE; // 父类
const char *name OBJC2_UNAVAILABLE; // 类名

long version OBJC2_UNAVAILABLE; // 类的版本信息,默认为0

long info OBJC2_UNAVAILABLE; // 类信息,供运行期使用的一些位标识

long instance_size OBJC2_UNAVAILABLE; // 该类的实例变量大小

struct objc_ivar_list *ivars OBJC2_UNAVAILABLE; // 该类的成员变量链表

struct objc_method_list **methodLists OBJC2_UNAVAILABLE; // 方法定义的链表

struct objc_cache *cache OBJC2_UNAVAILABLE; // 方法缓存,对象接到一个消息会根据isa指针查找消息对象,这时会在methodLists中遍历,如果cache了,常用的方法调用时就能够提高调用的效率。

struct objc_protocol_list *protocols OBJC2_UNAVAILABLE; // 协议链表
#endif
} OBJC2_UNAVAILABLE;

(二).了解类方法调用过程

NSObject
中有一个Class isa
的指针类型的成员变量,因为我们的对象大都直接或者间接的从NSObject继承而来,因此都会继承这个isa
成员变量,isa在运行时会指向对象的Class
对象,一个类的所有对象的Class
对象都是同一个(JAVA也是如此),这保证了在内存中每一个类型都有唯一的类型描述。这个Class
对象中也有个isa
指针,它指向了上一级的父类的Class对象。

在继承的时候,A extends B,你调用A
的方法a(),首先A
的isa
到A
的Class
对象中去查找a()方法,找到了就调用,如果没找到,就驱使A
的Class对象中的isa
到父类B
的Class
对象中去查找。 (Objective-C又提供了IMP类型,IMP表示指向实现方法的指针(函数指针),通过它,你可以直接访问一个实现方法,从而避免了[xxx
message]的静态调用方式,需要首先通过SEL确定方法,然后再通过IMP找到具体的实现方法,最后再发送消息所带来的执行效率问题。一般,如果你在多次循环中反复调用一个方法,用IMP的方式,会比直接向对象发送消息高效一些。 )

(三).具体实现过程
通过 isa指针的讲解,我们知道 Objective-C 中的方法调用是在运行时才去绑定的,再进一步看,编译器会把对象消息发送[xxx method]转换为objc_msgSend(id receiver,SEL selector,参数...)的函数调用。因此上面例子中的print 方法你也可以像下面这样调用:objc_msgSend(person,print_sel,@"++++++++");当然,这是编译器要做的事情,你在写代码的时候,是不需要直接使用这种写法的。

综合 isa、SEL、IMP的讲解,实际上 objc_msgSend的调用过程就应该是这样的。
A.首先通过第一个参数的receiver,找到它的isa 指针,然后在isa 指向的Class 对象中使用第二个参数selector 查找方法;

B.如果没有找到,就使用当前Class 对象中的新的isa 指针到上一级的父类的Class 对象中查找;

C.当找到方法后,再依据receiver 的中的self 指针找到当前的对象,调用当前对象的具体实现的方法(IMP指针函数),然后传递参数,调用实现方法.

{

SELprint_sel=NSSelectorFromString(@"print:");

IMPimp=[person
methodForSelector: print_sel];

imp(person,print_sel,@"*********");

}

D.假如一直找到NSObject
的Class
对象,也没有找到你调用的方法,就会报告不能识别.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: