isa 指针

Ojbective-C 中每个对象都有一个标明自己是什么对象的指针 – isa , 意为 “is a xxx”。 每一个类描述了一系列它的实例的特点,包括成员变量的列表,成员函数的列表等。下面是 Objective-C 非 2.0 版模型结构:

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;

那么这里的 isa 到底指向哪呢?

由于 Objective-C 中,一个类也是一个对象,所以它也必须是另一个类的实例,这个类就是元类 (metaclass) 。 元类保存了类方法的列表。当一个类方法被调用时,元类会首先找到本身是否有其实现,如果没有则向父类中查找。

元类也是一个对象,元类的 isa 指针则指向根元类 (root metaclass) 。而根元类的 isa 指向自己,这样就完成了一次闭环。

为了清楚的描述继承和 isa 指向的关系,苹果在官方文档中也给出了一个图例:

object

实线箭头表示继承关系,而虚线则表示 isa 指针指向。

到这里我们就大概能概括:

给一个类发消息,找元类继承链,给一个类的实例发消息,找类继承链。 实例 isa 指向类, 类 isa 指向元类, 元类 isa 指向根元类, 根元类 isa 指向自己。

###成员

从上面的 Objective-C 对象模型中可以看到,除了 isa 指针外还有很多其他成员,比如标记父类的 super_class , 应该用来表示类名的 name 等等。

version 为一个 long 类型, 应该表示这个对象的版本号。 instance_size 应该表示这个类对象大概在内存中占用的大小,从这个非 2.0 的结构体来看再考虑内存对齐应该不会超过一百个字节。(不考虑成员指针指向对象所占用的内存)

####Ivar

OC 对象中的 ivars 是指向成员属性列表的指针,来看下这个 objc_ivar_list :

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;
}    

有个数标记 ivar_count , 有空间标记 space 。

那么 ojbc_ivar 呢:

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
}    

名称标记 ivar_name , 类型标记 ivar_type , 空间标记 space , 而 ivar_offset 应该和内存对齐机制有关。

####Method

OC对象中的 methodList 是指向实例变量列表的指针,来看下这个 objc_method_list :

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;
}

obsolete 根据名字来猜,指向废弃的函数列表, method_count 是函数个数, space 为空间大小,然后继续来看下 objc_method :

struct objc_method {
    SEL method_name                                          OBJC2_UNAVAILABLE;
    char *method_types                                       OBJC2_UNAVAILABLE;
    IMP method_imp                                           OBJC2_UNAVAILABLE;
} OBJC2_UNAVAILABLE;

函数选择器 method_name , 描述类型(包含参数类型以及返回值类型)的字符串 method_types 以及函数指针 method_imp 。

####Cache

OC 对象中的 cache 对象类型为 objc_cache 的结构体 :

struct objc_cache {
    unsigned int mask /* total = mask + 1 */                 OBJC2_UNAVAILABLE;
    unsigned int occupied                                    OBJC2_UNAVAILABLE;
    Method buckets[1]                                        OBJC2_UNAVAILABLE;
};

Cache 为方法调用的性能进行优化,通俗地讲,每当实例对象接收到一个消息时,它不会直接在 isa 指向的类的方法列表中遍历查找能够响应消息的方法,因为这样效率太低了,而是优先在 Cache 中查找。 Runtime 系统会把被调用的方法存到 Cache 中(理论上讲一个方法如果被调用,那么它有可能今后还会被调用),下次查找的时候效率更高。

####Protocol

OC 对象中的 protocols 表示遵循的协议列表, 类型为 objc_protocol_list :

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

指向下一个协议列表的指针 next ,表示个数的 count 以及协议列表 list[1], Protocol :

@interface Protocol : NSObject
@end

可以看到 Protocol 也是一个类,具体成员这里就不再一一赘述了。

– EOF –

以上为这篇博客全部内容,欢迎提出建议,个人联系方式详见 关于