以前不太明白此函数具体实现过程,今天从相关资料总结出具体实现如下:
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、SEL、IMP的讲解,实际上 objc_msgSend的调用过程就应该是这样的。
B.如果没有找到,就使用当前Class 对象中的新的isa 指针到上一级的父类的Class 对象中查找;
C.当找到方法后,再依据receiver 的中的self 指针找到当前的对象,调用当前对象的具体实现的方法(IMP指针函数),然后传递参数,调用实现方法.
{
SELprint_sel=NSSelectorFromString(@"print:");
IMPimp=[person methodForSelector: print_sel];
imp(person,print_sel,@"*********");
D. 假如一直找到 NSObject 的 Class 对象,也没有找到你调用的方法,就会报告不能识别.