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

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

(一).认识类定义:

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 对象,也没有找到你调用的方法,就会报告不能识别.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值