最近特意看了很多篇关于runtime的文章。所以自己也想把了解的东西总结一下,以便以后大家一起学习。首先必须要诚实地说一句,这里都是看了别人的文章后,用自己的话总结出来的,而没有像其他额大牛样去用c语言去写一个swizzle method之类的。
首先要说,OC是一门运行时语言,因为它不像c++在编译的时候就会检查所有函数调用,而是运行时才会检查。
先来看看[target dosomething:varl];编译器会把它编译成什么:objc_msgsend(target,@selector(dosomething:),varl);你会发现这是一个c方法。那什么是runtime呢?runtime其实就是一个运势时的c语言写成的基础库,oc的程序必须得到runtime的的运行才能正常work。
下面我们来介绍一下对象和类。它们其实就是用c语言封装的结构体。(感受下面向对象与面向过程语言的区别)
oc里的class实际上就是一个objc_class结构体的指针:
typedef struct objc_class *Class;
struct objc_class {
Class isa OBJC_ISA_AVAILABILITY;
#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; // 方法缓存
struct objc_protocol_list *protocols OBJC2_UNAVAILABLE; // 协议链表
#endif
} OBJC2_UNAVAILABLE;
上图就是objc/runtime.h中objc_class 类的结构体的定义
其中以下参数是我们需要注意的:
1 isa:这个isa指向它所属的类,在运行时就靠这个指针来检测这个对象是否可以响应一个selector;需要注意的是在objective-c中,所有类自身也是一个对象,这个对象的class里面也有一个isa指针,它指向metaClass(元类 )。
2 super_class: 指向该类的父类,如果该类已经是最顶层的根类,则super_class为NULL;
3 cache:用于缓存最近使用的方法,一个接受者对象接受一个消息时,它会根据isa指针去查找能够响应这个消息的对象,有了这个缓存,每次调用runtime时,它就不需要每次都去方法链表中查找一边所有的方法,而是先去cache中进行查找;
好,我们来举个例子
NSArray * array = [[NSArray alloc] init];
其流程就是:
1、[NSArray alloc]先被执行,因为NSArray没有+alloc方法,于是就去父类NSObject中查找。
2、检测NSObject是否响应+alloc方法,发现响应,于是检测NSArray类,并根据其所需的内存空间大小开始分配内存空间,然后把isa指针指向NSArray类。同时,+alloc也被加进cahce;列表里。
3、接着,执行-init方法,如果NSArray响应该方法,则直接将其加入cache。如果不响应,则去父类查找。
4、在后期的操作中,如果再以[[NSArray alloc]init]这种方式创建数组的话,则会直接从cache中取出相应的方法,直接调用。
(更深层次的就不多说了,可以看这个链接的东西 http://southpeak.github.io/blog/2014/10/25/objective-c-runtime-yun-xing-shi-zhi-lei-yu-dui-xiang/)
objc_object与id
struct objc_object {
Class isa OBJC_ISA_AVAILABILITY;
};
typedef struct objc_object *id;
objc_object是表示一个类的实例的结构体,如上定义:
这里我们可以看到它只有一个指向其class 的isa指针。这样,当我们向一个对象发送消息时,runtime库(objc/runtime.h)就会根据isa指针找到相应的类。同时会在当前类的方法链表及其父类的列表方法中去寻找与selector指向对应的方法。
id,它就是一个objc_object结构类型的指针,它的存在可以让我们实现类似c++泛型的操作,有点类似void*指针类型的作用。
元类(meta Class)
上面我们提到,所有类自身也是一个对象,我们可以向这个对象发送消息(调用类方法)。
[NSArray array];
这里+array消息发送给了NSArray类,而这个NSArray也是一个对象。既然是对象,那么它也是一个objc_object指针,它包含一个指向其类的isa指针,那么isa指针指向哪里呢?为了调用+array,这个类的isa指针必须指向一个包含这些类方法的一个objc_class结构体。这就是meta-class ——是一个类对象的类。
当我们向一个对象发送消息时,runtime会在这个对象所属的这个类的方法列表中查找方法;而向一个类发送消息时,会在这个类的meta-class的方法中查找。meta-class会存储着一个类的所有类方法。每个类都会有一个独立的meta-class。meta-class也是一个类,那么它的isa指向什么呢?所有的isa指针都指向基类的meta-class。如,所有的NSObject继承体系下的meta-class都使用NSObject的meta-class作为自己的所属类,而meta-class的isa指针是指向它自己。
可以使用
objc_getClass((__bridge void*)[UIViewController class])
获取meta-class的指针地址。
OK,在讨论完这些底层数据结构之后,我们就可以来看看我们代码当中的具体使用了:
具体的以后有时间再解析:其实runtime无处不在,比如属性的使用KVC、消息和方法的使用@selector、对分类和协议的支持、block等!想要了解更多更详细的内容可以去刚才的那个网址仔细阅读。后续我也会把自己整理的东西陆续更新。。