在C++/Java/C#/OC等众多面向对象语言,它们都有着面相对象一些共有的特性,但是也都有各自的一些区别。今天我们就从运行时底层来剖析一下OC的特性。
- 先说说OC中的类
Person *person = [Person new];
Dog *dog = [Dog new];
Class class1 = [person class];
Class class2 = [dog class];
NSLog(@"%@ %@",class1,class2); //Person Dog
我们知道对象是由类实例化而来的。比如有一个Person类,我们就可以通过这个Person类实例化一个person对象,当我们用person这个对象调用class,会返回Class类型的对象。由此可见,当我们通过对象调用class方法的时候,就会返回该对象所属的类。比如person对象属于Person类,dog对象属于Dog类,所以 [person class] 打印的是Person类 ,[dog class] 打印的是Dog。
我们知道在OC中所有的类都是继承自NSObject的,那么这个Class为何物那?
打开Runtime底层源码,我们发现Class其实是一个结构体指针
/// An opaque type that represents an Objective-C class.
typedef struct objc_class *Class;
struct objc_class : objc_object {
Class superclass; // 父类
const char *name; // 类名
uint32_t version; // 类的版本信息,默认为0,可以通过runtime函数class_setVersion或者class_getVersion进行修改、读取
uint32_t info;
uint32_t instance_size;// 该类的实例变量大小(包括从父类继承下来的实例变量)
struct old_ivar_list *ivars; // 该类的成员变量地址列表
struct old_method_list **methodLists; // 方法地址列表
Cache cache;
struct old_protocol_list *protocols;
// CLS_EXT only
const uint8_t *ivar_layout;
struct old_class_ext *ext;
}
在objc_class 这个结构体中,又包含了指向其父类的结构体指针superclass、 该类名,该类下的成员变量列表、方法列表,协议列表等信息。既然知道在运行时底层类 (Class)是这样表示了,那么对象实例在底层是怎么表示的那??
/// Represents an instance of a class.
struct objc_object {
Class isa OBJC_ISA_AVAILABILITY;
};
/// A pointer to an instance of a class.
typedef struct objc_object *id;
id 是指向一个 objc_object 结构体的指针,也就是常说的万能指针。
由此可见,在底层每一个类的 “对象实例”其实也是一个结构体。这个结构体里只有一个成员变量(isa),这个isa是一个结构体指针,指向该对象实例所属的类(Class)。所以
通过该指针,对象就可以访问它所属的类以及相应的父类。
struct objc_class : objc_object {
Class superclass;
...
}
可以看出objc_class继承自objc_object,所以objc_class也有一个isa指针。
可见OC中万物皆对象,Class本身其实也是对象,有的资料中将其称为类对象,
类对象的也有对应的类,我们叫它 元类(Meta Class),而objc_class中的isa指针指向的就是它的元类(Meta Class)
为了更好的理解对象,类对象、元类的关系,可以参考下面这幅图:
注: 实线尖头代表即成关系,虚线肩头代表isa指针的指向
Instance 表示对象实例、class代表类(或称:类对象)、meta 代表元类
1. 每一个instance(对象实例)都有一个isa指针,指向其对应的Class(类或者类对象)
2. 每一个Class(类或者类对象)都有一isa指针指向其对应的元类(Meta Class)
3. Meta Class本身也是一个Class,它跟其他Class一样也有自己的 isa 和 super_class 指针,每一个Meta Class的isa指针都指向最上层的元类(Meta Class),最上层的Meta Class的isa指针指向自己。
4. 那这个最上层的Meta Class是哪里来的那,它的super_class又是谁那??
最上层的Meta Class 它的父类就是最上层的Root Class,就是上面实线尖头所指向的。在OC中这个最上层的Root Class其实就是NSObject Class本身。
5. 最上层的Root Class的super class指向 nil
最后,我们都知道在OC中方法分为 类方法和对象方法(也叫实例方法),那么试想一下这些方法保存在什么地方那?对象方法是保存是对象实例中吗? 类方法是保存在类中吗?
这种想法显然不可取,因为我们每创建一个对象实例,它们都是一样的,假如每一个对象实例都保存一次方法,显然是很浪费资源的;于是就让对象方法保存在其对应的Class(类或者类对象)中,让类方法保存在其对应的元类(Meta Class)中。
据上面的描述,简单的说:
- 当调用一个对象的对象方法时,就会在对象对应的Class的“方法列表”里查找
- 当我们发送一个消息给一个类时,这条消息会在类的Meta Class的方法列表里查找