Objective-C总Runtime的那点事儿 消息机制

RunTime简称运行时。就是系统在运行的时候的一些机制,其中最主要的是消息机制。对于C语言,函数的调用在编译的时候会决定调用哪个函数。编译完成之后直接顺序执行,如任何二义性。OC的函数调用成为消息发送。属于动态调用过程。在编译的时候并不能决定真正调用哪个函数(事实证明,在编译阶段,OC可以调用任何函数,即使这个函数并未实现,只要声明过就不报错。而C语言在编译阶段就会报错)。只有在真正运行的时候才会根据函数的名称找到对应的函数来调用.

那OC是怎么实现动态调用的呢?下面我们来看看OC通过发送消息来达到动态调用的秘密。假如在OC中写了这个的一个代码
[obj makeText];

其中obj是一个对象,makeText是一个函数名称。对于这样一个简单的调用。在编译时RunTime会将上述代码转成
objc_msgSend(obj,@selector(makeText));

首先我们来看看obj这个对象,iOS中obj都继承于NSObject。
@interface NSObject {

Class isa OBJC_ISA_AVAILABILITY;

}

在NSObject 中存在一个Class的isa指针。然后我们看看Class:
typedef struct objc_class *Class;
struct objc_class{

Class isa;//指向
Class super_class;//指向其父类
const char *name;//类名
long version ; // 类的版本信息,初始化默认为0,可以通过runtime函数class_setVersion和class_getVersion进行修改、读取

long info; // 一些标识信息,如CLS_CLASS (0x1L) 表示该类为普通 class ,其中包含对象方法和成员变量;CLS_META (0x2L) 表示该类为 metaclass,其中包含类方法;

long instance_size ; // 该类的实例变量大小(包括从父类继承下来的实例变量);

struct objc_ivar_list *ivars; // 用于存储每个成员变量的地址

struct objc_method_list **methodLists ; // 与 info 的一些标志位有关,如CLS_CLASS (0x1L),则存储对象方法,如CLS_META (0x2L),则存储类方法;

struct objc_cache *cache; // 指向最近使用的方法的指针,用于提升效率;

struct objc_protocol_list *protocols; // 存储该类遵守的协议
}

我们可以看到,对于一个Class类中,存在很多东西,下面我来一一解释一下:
Class isa:指向metaclass,也就是静态的Class。一般一个Obj对象中的isa会指向普通的Class,这个Class中存储普通成员变量和对象方法(“-”开头的方法),普通Class中的isa指针指向静态Class,静态Class中存储static类型的成员变量和类方法(“+”开头的方法)。
Class super_class :指向父类,如果这个类是根类,则为NULL。
下边一张图片很好的描述了类和对象的继承关系:
这里写图片描述
注意:所有metaclass中isa指针都指向metaclass。而跟metaclass则指向自身。Root metaclass是通过继承Root class产生的。与root class结构体成员一致,也就是前面提到的结构。不同的是Root metaclass的isa指针指向自身。
Class类中其他的成员这里就先不做过多解释了,下面我们来看看:

@selector(makeText): 这是一个SEL方法选择器。SEL其主要作用是快速的通过方法名字(makeText)查找到对应的方法的函数指针,然后调用其函数。SEL其本身是一个Int类型的地址,地址中存放着方法的名字。对于一个类中 每一个方法对应着一个SEL。所以iOS类中不能存在2个名称相同的方法,即使参数类型不同,因为SEL是根据方法名字生成的,相同的方法名称只能对应一个SEL。

下面我们就来看看具体消息发送之后是怎么动态查找对应的方法的。
首先,编译器将代码【obj makeText】;转化为objc_msgSend(obj,@selectior(makeText));在objc_msgSend函数中。
首先通过obj的isa指针找到obj对应的class。在Class中先去cache中通过SEL查找对应函数method(猜测cache中method列表是以SEL为key通过hash表来存储的,这样能提高函数查找速度),若case中未找到。再去methodList中查找,若methodist中未找到,则去superClass中查找。若能找到则将method加入到cache中以方便下次查找,并通过method中的函数指针跳转到对应的函数中去执行。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值