Runtime之对象、类(类对象)、元类

来源:互联网 发布:java中final修饰的类 编辑:程序博客网 时间:2024/05/17 20:31

在C++/Java/C#/OC等众多面向对象语言,它们都有着面相对象一些共有的特性,但是也都有各自的一些区别。今天我们就从运行时底层来剖析一下OC的特性。


  1. 先说说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的方法列表里查找

参考资料:http://blog.csdn.net/hmxhh/article/details/41281681
https://www.ianisme.com/ios/2019.html 






0 0