高效编写代码的方法(十二):类的内省

前言

在之前几篇文章中,我们了解到了一个类的方法是怎么在类中进行存储的;当一个类的实现方法无法找到时,消息转发机制又是如何起作用的。所以,接下来我们要去了解 类 的本身,也就是消息的接收者(receiver)。
在运行时候,我们的程序是怎么知道该像哪一个类去寻找消息的实现呢?

内省

一般来说,如果我们像指定类的实例对象发送消息之后,编译器会检查该类是否有该消息方法的接口,如果没有则会抛出报错或警告。但是对于id这种特殊的类(id可以代表任何一个NSObject),所以编译器会假设id可以对任何消息做出反应而不抛出报错或警告,但在实际运行时可能崩溃。
同时因为objc中类的方法是可以动态进行添加的,所以编译器的检查对于objc来说已经不足够了。

runtime提供了一种类的内省机制,这其中包括了isKindOfClass等我们经常会使用到的方法,这些方法都是NSObject的protocol一部分,所以所有的对象都具有这一套内省方法。

结构

在runtime中,对象以结构构体保存,id类的对象的结构体如下:

typedef struct objc_object {  
    Class isa;  
} *id; 

由此可见,其中包含一个Class类的变量isa,isa指向该对象的类。
所以NSString *str , str中的isa就指向NSString。

Class对象在runtime中也有结构体定义:

typedef struct objc_class *Class;  
struct objc_class {  
    Class isa;  
    Class super_class;  
    const char *name;  
    long version;  
    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本身也是一个Objective-C对象。结构体里还有个变量叫做super_class,它指向了该类的父类。类对象所属的类型(也就是isa指针所指向的类型)是另外一个类,叫做“元类”(metaclass)。
metaClass是用来描述这个类的数据的一个对象。


高效编写代码的方法(十二):类的内省_第1张图片
类的关系图

isKindOfClass和isMemberOfClass的具体使用就不多说了,两个方法都是通过结构体内的isa指针和super_class指针来确定该类的继承关系。
猜想一下isMemberOfClass可能就是通过isa来判断,而isKindOfClass就主要是通过super_class来实现查找判断。

总结

  • 1 每个对象都有一个指向Class对象的指针,用来表明类型,而这些Class对象则构成了类的继承体系。
  • 2 如果对象类型无法在编译期确定,那么就应该使用内省方法来探知。
  • 3 尽量使用类型信息查询方法来确定对象类型,而不要直接比较类对象,因为某些对象可能实现了消息转发功能。

你可能感兴趣的:(高效编写代码的方法(十二):类的内省)