概述
OC正是由于有了runtime才使得c语言具有了面向对象的能力,在程序的运行时刻,创建,检查,修改类、对象以及类、对象的方法。
为什么会这么说?OC中的对象、类又到底是一个什么样的数据结构,对象、类又是如何用C来描述的呢?带着这样的问题,我们首先来看一下在OC中类的定义。
Class
在objc/runtime.h中objc_class结构体的定义如下:
struct objc_class {
Class isaOBJC_ISA_AVAILABILITY;//isa指针指向Meta Class,因为objc类本身也是一个object(对象),为了处理这个关系,runtime创造了Meta Class,当一个类发送[NSObject alloc]这样消息时,实际上是把消息发送给Class object类对象
#if !__OBJC2__
Class super_classOBJC2_UNAVAILABLE;//父类
const char *nameOBJC2_UNAVAILABLE;//类名
long versionOBJC2_UNAVAILABLE;//类的版本信息,默认为0
long infoOBJC2_UNAVAILABLE;//类信息,供运行时使用的一些位表示
long instance_sizeOBJC2_UNAVAILABLE;//该类的实例变量大小
struct objc_ivar_list *ivarsOBJC2_UNAVAILABLE;//该类的成员变量的链表
struct objc_method_list **methodListsOBJC2_UNAVAILABLE;//方法定义的链表
struct objc_cache *cacheOBJC2_UNAVAILABLE;//方法缓存,对象接到一个消息会根据isa指针查找消息对象,这时会在methodLists中遍历,如果cache了,常用的方法调用时就能够提高调用的效率。
struct objc_protocol_list *protocolsOBJC2_UNAVAILABLE;//协议链表
#endif
} OBJC2_UNAVAILABLE;
在objc.h中有这样一个定义
/// An opaque type that represents an Objective-C class.
typedef struct objc_class *Class;
即:OC当中任何一个类都是用objc_class这样一个结构体来描述的。
objc_object与id
objc_object是一个类的实例结构体,objc/objc.h中objc_object是一个类的实例结构体定义如下:
struct objc_object {
Class isa OBJC_ISA_AVAILABILITY;
};
typedef struct objc_object *id;
与objc_class相同,在OC当中用一个结构体描述一个对象;在向object发送消息的时候,runtime会根据object的isa指针找到这个实例的object所属于的类,然后在类的方法列表以及父类的方法列表中寻找对应的方法运行。
id是一个objc_object结构类型的指针,这个类型的对象能够转换任何一种对象。
Meta Class
大家可能注意到,一个对象的isa指针会指向它的类。然而在面向对象的世界里,一切都是对象,即:一个类也是一个对象,那么问题来了,那这个类对象它的类是谁呢(可能有点绕大家稍微理解一下这觉话)?类对象的isa指针又会指向哪里呢?
为了解决这个问题,runtime创造了元类(Meta Class)。即一个类的是它元类的实例话,一个类的isa指针是指向它的元类。和对象一样,我们向一个类发送消息的时候,isa指针会在元类中以及元类的父类方法列表寻找对应的方法运行。
既然一切都是对象那么元类也是对象,那么元类的类是谁?元类的isa指针指向哪里呢?下面这张经典的图完美了解释了一些,废话少说上图:
即任何一个元类都是根元类的对象,任何一个元类的isa指针都指向了根元类;而根元类的isa指针又指向了它自己;形成了一个闭环,这样就完美的诠释了面向对象的世界里万物皆对象的概念。(这张图,大家一定要好好的理解一下,如果今天看不懂,那么我给的建议是明天再看一遍,如果明天还看不懂,那就后天,如果还是不懂,那就过段时间再来看,如此反复,直到成功)
好吧,到这里大家应该明白了,oc其实就是在用c的结构体来描述类和对象,通过一个isa指针指来指去完成了方法的调用,对于c系的同学来说应该不会有太大的难度。。。
后面会继续写关于runtime的知识。今天就先到这里吧,打卡,下班,回家。。。
顺道拜托,若文中有任何理解不正确的地方欢迎指出