个人对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
对象,也没有找到你调用的方法,就会报告不能识别.
相关文章推荐
- 解析包的关键字 获得handler 映射到具体的实现函数 client_packet.h
- Java Serializable(序列化)的理解和总结、具体实现过程
- C 某些库函数中字符串处理函数的具体实现
- mysql存储过程的坑(关于declare与具体实现顺序)
- priority_queue 的具体实现及比较函数
- C语言中,函数的具体执行过程。
- 反汇编分析objc函数枢纽objc_msgSend
- 用 WebService 实现 Silverlight 客户端调用第三方动态链接库(Fortran DLL)的具体过程
- OpenGL学习笔记(二):OpenGL语法、渲染管线以及具体实现过程详解
- Hive中实现自定义函数UDF详细过程
- strstr()函数的具体实现
- delphi实现函数/过程
- R语言函数的含义与用法,实现过程解读
- 解读linux对string.h函数的实现
- 理解函数调用实现过程 栈结构 栈过程
- Nagios 监控mysqlserver具体实现过程
- 函数调用具体过程-堆栈【1】
- OpenCV中resize函数五种插值算法的实现过程
- 线性表顺序存储结构的具体实现过程--java