【iOS面试粮食】Runtime—实例对象、类对象、元类对象

本文章将记录Objective-C中实例对象、类对象、元类对象的相关资料,如有错误欢迎指出~

实例对象(InstanceObject)

实例对象是类实例化的对象,代表着某一个具体的东西。在OC中表现为:

Person *man = [Person new];

Person是类, man就是Person实例化的对象,代表着一个具体的东西,即男人。

实例对象是我们对类对象alloc或者new操作时所创建的,在这个过程中会拷贝实例所属的类的成员变量,但并不拷贝类定义的方法。调用实例方法时,系统会根据实例的isa指针去类的方法列表及父类的方法列表中寻找与消息对应的selector指向的方法。我们来看下其定义:

/// Represents an instance of a class.
struct objc_object {

    Class _Nonnull isa  OBJC_ISA_AVAILABILITY;

};

这个结构体只有一个isa变量,指向实例对象所属的类。任何带有以指针开始并指向类结构的结构都可以被视作objc_object, 对象最重要的特点是可以给其发送消息。

类对象(Class)

类对象是由程序员定义并在运行时由编译器创建的,它没有自己的实例变量,这里需要注意的是类的成员变量和实例方法列表是属于实例对象的,但其存储于类对象当中的。我们看看Class的定义:

/// An opaque type that represents an Objective-C class.

typedef struct objc_class *Class;

可以看到类是由Class类型来表示的,它是一个objc_class结构类型的指针。我们接着来看objc_class结构体的定义:

struct objc_class {

  Class           isa;      // 指向所属类的指针(_Nonnull)

  Class           super_class;  // 父类         

  const char        *name;     // 类名(_Nonnull)

  long            version;    // 类的版本信息(默认为0)

  long            info;     // 类信息(供运行期使用的一些位标识)

  long            instance_size; // 该类的实例变量大小

  struct objc_ivar_list   *ivars;     // 该类的成员变量链表

  struct objc_method_list * *methodLists;  // 方法定义的链表

  struct objc_cache     *cache;     // 方法缓存

  struct objc_protocol_list *protocols;   // 协议链表

};
  • isa指针是和Class同类型的objc_class结构指针,类对象的指针指向其所属的类,即元类。元类中存储着类对象的类方法,当访问某个类的类方法时会通过该isa指针从元类中寻找方法对应的函数指针

  • super_class为该类所继承的父类对象,如果该类已经是最顶层的根类(如NSObject或NSProxy), 则 super_class为NULL

  • ivars是一个指向objc_ivar_list类型的指针,用来存储每一个实例变量的地址

  • info为运行期使用的一些位标识,比如:

    CLS_CLASS (0x1L)表示该类为普通类, CLS_META (0x2L)则表示该类为元类

  • methodLists用来存放方法列表,根据info中的标识信息,当该类为普通类时,存储的方法为实例方法;如果是元类则存储的类方法

  • cache用于缓存最近使用的方法。系统在调用方法时会先去cache中查找,在没有查找到时才会去methodLists中遍历获取需要的方法

元类对象(Metaclass)

元类就是类对象的类,每个类都有自己的元类,也就是objc_class结构体里面isa指针所指向的类. Objective-C的类方法是使用元类的根本原因,因为其中存储着对应的类对象调用的方法即类方法。

类存储示意图

所以由上图可以看到,在给实例对象或类对象发送消息时,寻找方法列表的规则为:

  • 当发送消息给实例对象时,消息是在寻找这个对象的类的方法列表(实例方法)
  • 当发送消息给类对象时,消息是在寻找这个类的元类的方法列表(类方法)

元类,就像之前的类一样,它也是一个对象,也可以调用它的方法。所以这就意味着它必须也有一个类。所有的元类都使用根元类作为他们的类。比如所有NSObject的子类的元类都会以NSObject的元类作为他们的类。

根据这个规则,所有的元类使用根元类作为他们的类,根元类的元类则就是它自己。也就是说基类的元类的isa指针指向他自己。

为了更好的理解对象,类对象、元类的关系,可以参考下面这幅图:

类关系示意图

总结一下实例对象,类对象以及元类对象之间的isa指向和继承关系的规则为:

  • 实例对象的isa指向该类,类的isa指向元类(metaClass)
  • 类的superClass指向其父类,如果该类为根类则值为nil
  • 元类的isa指向根元类,如果该元类是根元类则指向自身
  • 元类的superClass指向父元类,若根元类则指向该根类

参考

OC底层原理之实例、类对象、元类对象

格物致知iOS类与对象

你可能感兴趣的:(【iOS面试粮食】Runtime—实例对象、类对象、元类对象)