浅析运行时Runtime

来源:互联网 发布:隆德大学 知乎 编辑:程序博客网 时间:2024/05/13 20:02

运行时

Objective-C是一门简单的语言,底层95%都是C语言,经过了一层封装,具有了面向对象的能力。Objectice-runtime其实是一个runtime库,真正让OC强大的就是这个高级特性运行时。

在这个库中,对象可以用C语言中的结构体表示,而方法可以用C函数来实现,另外再加上了一些额外的特性。这些结构体和函数被runtime函数封装后,我们就可以在程序运行时创建,检查,修改类、对象和它们的方法。

这里讲一下关于消息。执行一个方法,有些语言,编译器会执行一些额外的优化和错误检查,因为调用关系很直接也很明显,但对于消息分发来说,就不name明显了。在发消息前不必知道某个对象是否能够处理消息,你把消息发给它,它可能会处理,也可能转给其他的Object来处理。一个消息不必对应一个方法,一个对象可能实现一个方法来处理多条消息。在OC中,消息是通过objc_msgSend()这个runtime方法以及相近的方法来实现的,这个方法需要一个target,selector,还有一些参数。理论上来说,编译器只是把消息分发编程object_msgSend来执行。比如下图两行代码是等价的:



Objective-C runtime目前有两个版本:Modern runtime和Legacy runtime。Modern Runtime 覆盖了64位的Mac OS X Apps,还有 iOS Apps,Legacy Runtime 是早期用来给32位 Mac OS X Apps 用的,也就是可以不用管就是了

ARC是在运行时完成对象的retain和release,由编译器自动完成,不需要程序员参与手动执行,内部运用运行时原理,在程序执行过程中实现。

大多数情况下,运行时系统仅在幕后自动工作,主要用于编写和编译Objective-C源程序。OC编译器Clang可以将OC源程序重写为CPP的代码,从而可以实现看到底层运行时的实现原理,是了解OC实现原理的重要手段之一。实现步骤:打开终端->cd项目文件目录->clang-rewrite-objc main.m ->open main.cpp ,这样我们可以更清晰的了解底层实现机制,重写的越简单越好。
isa 指针

Ojbective-C 中每个对象都有一个标明自己是什么对象的指针 – isa , 意为 “is a xxx”。 每一个类描述了一系列它的实例的特点,包括成员变量的列表,成员函数的列表等。下面是 Objective-C 非 2.0 版模型结构:


正如上述所说,因为类也是一个对象,那它也必须是另一个类的实列,这个类就是元类(metaclass)。元类保存了类方法的列表。当一个类方法被调用时,元类会首先查找它本身是否有该类方法的实现,如果没有,则该元类会向它的父类查找该方法,直到一直找到继承链的头。
元类(metaclass)也是一个对象,那么元类的isa指针又指向哪里呢?为了设计上的完整,所有的元类的isa指针都会指向一个根元类(root metaclass)。根元类(root metaclass)本身的isa指针指向自己,这样就行成了一个闭环。上面提到,一个对象能够接收的消息列表是保存在它所对应的类中的。在实际编程中,我们几乎不会遇到向元类发消息的情况,那它的isa指针在实际上很少用到。不过这么设计保证了面向对象的干净,即所有事物都是对象,都有isa指针
 (tagged pointer 例外)。
我们再来看看继承关系,由于类方法的定义是保存在元类(metaclass)中,而方法调用的规则是,如果该类没有一个方法的实现,则向它的父类继续查找。所以,为了保证父类的类方法可以在子类中可以被调用,所以子类的元类会继承父类的元类,换而言之,类对象和元类对象有着同样的继承关系。

那么这里的isa到底指向哪呢?

由于OC中,一个类也是一个对象,所以它也必须是另一个类的实例,这个类就是元类(metaclass)。元类保存了类方法的列表。当一个类方法被调用时,元类会首先找到本身是否有其实现,如果没有则向父类中查找。元类也是一个对象,元类的isa指针则指向根元类(root metaclass)。而根元类的isa指向自己,这样就完成了一次闭环。

为了了清楚的描述继承和isa指向的关系,苹果在官方文档中也给出了这样一个图例:


实线箭头表示继承关系,而虚线则表示isa指针指向。

概括来说就是:给一个类发消息,找元类继承链,给一个类的实例发消息,找累继承链。实例isa指向类,类isa指向元类,元类isa指向根元类,根元类isa指向自己。

下面是写了一个demo及打印,可以很好的解释类,元类,根元类之间的关系。


其它成员变量:
  super_class:这个指针就是指向该class的super class,即指向父类,如果该类已经是最顶层的根类(如NSObject或NSProxy),则super_class为NULL。
  objc_cache:用于缓存最近使用的方法。一个接收者对象接收到一个消息时,它会根据isa指针去查找能够响应这个消息的对象。在实际使用中,这个对象只有一部分方法是常用的,很多方法其实很少用或者根本用不上。这种情况下,如果每次消息来时,我们都是methodLists中遍历一遍,性能势必很差。这时,cache就派上用场了。在我们每次调用过一个方法后,这个方法就会被缓存到cache列表中,下次调用的时候runtime就会优先去cache中查找,如果cache没有,才去methodLists中查找方法。这样,对于那些经常用到的方法的调用,但提高了调用的效率。
  version:我们可以使用这个字段来提供类的版本信息。这对于对象的序列化非常有用,它可是让我们识别出不同类定义版本中实例变量布局的改变。
  objc_method_list方法链表中存放的是该类的成员方法(-方法),类方法(+方法)存在meta-class的objc_method_list链表中,可以通过修改 objc_method_list指针指向的指针的值 可以动态地 为某一个类增加成员方法 这也是 category 实现的原理。

参考博客:http://limboy.me/ios/2013/08/03/dynamic-tips-and-tricks-with-objective-c.html
              http://rannie.github.io/ios/2015/02/13/oc-object.html


1 0
原创粉丝点击