从设计结构上来看关于oc的分类添加属性后不能自动生成成员变量,但能动态添加方法

在objc2之后class的结构是这样的

struct objc_class : objc_object {

    // Class ISA;    Class superclass;

    cache_t cache;            // formerly cache pointer and vtable 

class_data_bits_t bits;    // class_rw_t * plus custom rr/alloc flags

}


这里的bits是个共用体union

bits & mask之后获得一个结构体 class_rw_t:

struct class_rw_t {

    uint32_t flags;

    uint32_t version;

    const class_ro_t *ro;

    method_array_t methods;

    property_array_t properties;

    protocol_array_t protocols;

    Class firstSubclass;

    Class nextSiblingClass;

    char *demangledName;

}



const class_ro_t *ro

struct class_ro_t {

    uint32_t flags;

    uint32_t instanceStart;

    uint32_t instanceSize;#ifdef __LP64__    uint32_t reserved;#endif    const uint8_t * ivarLayout;

    const char * name;

    method_list_t * baseMethodList;

    protocol_list_t * baseProtocols;

    const ivar_list_t * ivars;

    const uint8_t * weakIvarLayout;

    property_list_t *baseProperties;

    method_list_t *baseMethods() const {

        return baseMethodList;

    }

};

class_rw_t顾名思义,拥有读写权限,ro就是只读的意思,ivars放在class_ro_t里面,所以ivar在编译时期已经是固定的了,之后不能动态的添加更改,但是property,和methods在rw_t里面,所以可以允许动态添加。

还要就是instanceSize也是放在class_ro_t里的,所以类的大小是在编译时期已经决定的了。可以这么理解,ivars放在class_rw_t,那有可能以后获得size就错误。

二:那为啥会是这样的设计呢?

其实也不难。成员变量,属性其实都是属于它的实例的,不同的实例,他们的成员变量都是不同的,所以他们都存储在所在实例的堆空间中,互不干扰,而且加入程序运行后再动态添加属性,那该类原来的子类的空间布局是不是也要相应的做出改变呢?。但是方法确实公用的,不同的实例所调用的方法都是一样的,而且我们也知道,方法其实是存在于代码区的,所以即使动态的添加方法,也不影响原来架构和功能。

你可能感兴趣的:(从设计结构上来看关于oc的分类添加属性后不能自动生成成员变量,但能动态添加方法)