美文网首页
高效编写代码的方法(十二):类的内省

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

作者: 蜂猴 | 来源:发表于2016-05-16 18:19 被阅读117次

    前言

    在之前几篇文章中,我们了解到了一个类的方法是怎么在类中进行存储的;当一个类的实现方法无法找到时,消息转发机制又是如何起作用的。所以,接下来我们要去了解 类 的本身,也就是消息的接收者(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是用来描述这个类的数据的一个对象。


    类的关系图

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

    总结

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

    相关文章

      网友评论

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

          本文链接:https://www.haomeiwen.com/subject/gbvbrttx.html