iOS RuntimeiOS

OC中的类是怎么来的?

2015-11-14  本文已影响300人  FITZ9311

博客地址:张飞的技术博客
我们都知道OC是在C语言的基础上增加了面向对象的编程特性。我们知道C语言并没有面向对象中的类的概念。细心的小伙伴会发现,C语言的结构体和类长得有点像。难道OC中的类和C语言的结构体有渊源?是的,你没有猜错,OC是一门动态语言,有一套运行时机制,会把OC中的类动态构造为C语言的结构体,不信?且往下看。Objective-C类是由Class类型来表示的。在objc.h中可以找到OC中类的定义,如下:

/// An opaque type that represents an Objective-C class.
typedef struct objc_class *Class;

从这里可以看出来OC中的类其实是C语言中的一个结构体指针,它指向了objc_class这个结构体。进一步跟踪,在runtime.h可以看到objc_class的定义,如下(根据我自己的理解添加了注释):

struct objc_class {
    Class isa  OBJC_ISA_AVAILABILITY;  //指向自己的真实类型

#if !__OBJC2__
    Class super_class                        OBJC2_UNAVAILABLE;  //指向父类
    const char *name                         OBJC2_UNAVAILABLE;  //类名
    long version                             OBJC2_UNAVAILABLE;  //类的版本
    long info                                OBJC2_UNAVAILABLE;  //类的信息
    long instance_size                       OBJC2_UNAVAILABLE;  //类实例大小
    struct objc_ivar_list *ivars             OBJC2_UNAVAILABLE;  //类的成员变量链表
    struct objc_method_list **methodLists    OBJC2_UNAVAILABLE;  //类的方法定义链表
    struct objc_cache *cache                 OBJC2_UNAVAILABLE;  //方法缓存
    struct objc_protocol_list *protocols     OBJC2_UNAVAILABLE;  //类的协议链表
#endif

} OBJC2_UNAVAILABLE;

详细看一下结构体的成员变量是干啥的吧。

struct objc_ivar_list {
    int ivar_count                                           OBJC2_UNAVAILABLE;
#ifdef __LP64__
    int space                                                OBJC2_UNAVAILABLE;
#endif
    /* variable length structure */
    struct objc_ivar ivar_list[1]                            OBJC2_UNAVAILABLE;
} 

objc_ivar_list这个结构体里面还有一个objc_ivar的结构体,它的声明就objc_ivar_list这个结构体的上面,声明是这个样子的:

struct objc_ivar {
    char *ivar_name                                          OBJC2_UNAVAILABLE;
    char *ivar_type                                          OBJC2_UNAVAILABLE;
    int ivar_offset                                          OBJC2_UNAVAILABLE;
#ifdef __LP64__
    int space                                                OBJC2_UNAVAILABLE;
#endif
}
struct objc_method_list {
    struct objc_method_list *obsolete                        OBJC2_UNAVAILABLE;

    int method_count                                         OBJC2_UNAVAILABLE;
#ifdef __LP64__
    int space                                                OBJC2_UNAVAILABLE;
#endif
    /* variable length structure */
    struct objc_method method_list[1]                        OBJC2_UNAVAILABLE;
}

在这个结构体的声明里面可以看到里面有一个叫objc_method_list的结构体指针,这样我们不就不难理解它是一个指针的指针了。这里面的结构体objc_method的定义如下:

struct objc_method {
    SEL method_name                                          OBJC2_UNAVAILABLE;
    char *method_types                                       OBJC2_UNAVAILABLE;
    IMP method_imp                                           OBJC2_UNAVAILABLE;
}
struct objc_cache {
    unsigned int mask /* total = mask + 1 */                 OBJC2_UNAVAILABLE;
    unsigned int occupied                                    OBJC2_UNAVAILABLE;
    Method buckets[1]                                        OBJC2_UNAVAILABLE;
};

也许你会发现一个Method的类,其实他的本质就是上面的objc_method这个结构体。

struct objc_protocol_list {
    struct objc_protocol_list *next;
    long count;
    Protocol *list[1];
};

这下明白了吧,OC的类和C语言还有这么一层关系,当然这都归功于OC的Runtime机制。

在面向对象编程中不仅有类的概念,还有实例对象的概念,既然类与C语言的结构体有着千丝万缕的关系,那么,类对象想必也和C语言撇不开关系吧。是的,有什么关系呢?往下看!

上面说了类是怎么构造的,那你不禁会问类对象是怎么构造的呢?其实就在objc.h文件里声明Class结构体下面就可以发现这样的代码:

/// Represents an instance of a class.
struct objc_object {
    Class isa  OBJC_ISA_AVAILABILITY;
};

从注释中不难看出,结构体objc_object表示的是类对象,可以看到,这个结构体只有一个成员变量,即指向其类的isa指针。这样,当我们向一个Objective-C对象发送消息时,运行时库会根据实例对象的isa指针找到这个实例对象所属的类。Runtime库会在类的方法列表及父类的方法列表中去寻找与消息对应的selector指向的方法。找到后即运行这个方法。也就是是说当我们创建一个特定类的实例对象时,分配的内存包含一个objc_object数据结构,然后是类的实例变量的数据。

结尾

上面讲的都要归功于牛逼的Runtime,那么Runtime有什么🐂👃的呢?有兴趣就看我的下一片文章。最后大家不要忘了,如果我的文章对你有帮助,你愿意请我喝杯茶的话,请用支付宝扫一扫下面的二维码随意打赏。祝大家玩得愉快!


上一篇下一篇

猜你喜欢

热点阅读