美文网首页
Objective-C类

Objective-C类

作者: kwdx | 来源:发表于2018-03-08 15:27 被阅读0次

    今天,我打算说说自己对于Objective-C中的类的理解。Objective-C中的类在编译的时候首先会编译成C语言,这时候类就变成了C语言的结构体了。

    1. Class的实际结构

    struct _class_t {
        struct _class_t *isa;           // isa指针
        struct _class_t *superclass;    // 父类
        void *cache;
        void *vtable;
        struct _class_ro_t *ro;         // 包含class的信息
    };
    /// 具体的_class_ro_t结构如下
    struct _class_ro_t {
        unsigned int flags;
        unsigned int instanceStart;  // 实例对象的起始地址
        unsigned int instanceSize;  // 实例对象占用的内存大小
        unsigned int reserved;
        const unsigned char *ivarLayout;
        const char *name;                                   // 类名
        const struct _method_list_t *baseMethods;           // 方法列表
        const struct _objc_protocol_list *baseProtocols;    // 协议列表
        const struct _ivar_list_t *ivars;                   // ivar列表
        const unsigned char *weakIvarLayout;                // 猜测是weak修饰的ivar
        const struct _prop_list_t *properties;              // 属性列表
    };
    

    我们先定义两个个简单的OC类Father和Son

    • Father
    @interface Father : NSObject
    @property (nonatomic, copy) NSString *name;
    @end
    @implementation Father
    + (instancetype)fatherWithName:(NSString *)name {
        Father *father = [[[self class] alloc] init];
        father.name = name;
        return father;
    }
    - (instancetype)initWithName:(NSString *)name {
        if (self = [[[self class] alloc] init]) {
            self.name = name;
        }
        return self;
    }
    @end
    
    • Son
    @interface Son : Father
    {
        NSUInteger _age;
    }
    @end
    @implementation Son
    + (instancetype)sonWithName:(NSString *)name age:(NSUInteger)age {
        Son *son = [super fatherWithName:name];
        son->_age = age;
        return son;
    }
    - (instancetype)initWithName:(NSString *)name age:(NSUInteger)age {
        if (self = [super initWithName:name]) {
            self->_age = age;
        }
        return self;
    }
    @end
    

    我们通过clang -rewrite-objc main.m能得到重写后的纯C代码,并找到FatherSon_class_t结构

    // Father
    struct _class_t OBJC_CLASS_$_Father = {
        0, // &OBJC_METACLASS_$_Father,
        0, // &OBJC_CLASS_$_NSObject,
        0, // (void *)&_objc_empty_cache,
        0, // unused, was (void *)&_objc_empty_vtable,
        &_OBJC_CLASS_RO_$_Father,
    };
    // Son
    struct _class_t OBJC_CLASS_$_Son = {
        0, // &OBJC_METACLASS_$_Son,
        0, // &OBJC_CLASS_$_Father,
        0, // (void *)&_objc_empty_cache,
        0, // unused, was (void *)&_objc_empty_vtable,
        &_OBJC_CLASS_RO_$_Son,
    };
    

    再来看看_class_ro_t定义些什么

    • Father
    static struct _class_ro_t _OBJC_CLASS_RO_$_Father = {
        0, __OFFSETOFIVAR__(struct Father, _name), sizeof(struct Father_IMPL), 
        (unsigned int)0, 
        0, 
        "Father",   // 类名
        (const struct _method_list_t *)&_OBJC_$_INSTANCE_METHODS_Father,    // 方法列表
        0,                                                                  // 协议列表
        (const struct _ivar_list_t *)&_OBJC_$_INSTANCE_VARIABLES_Father,    // ivar列表
        0,                                                                  // weak修饰的ivar
        (const struct _prop_list_t *)&_OBJC_$_PROP_LIST_Father,             // 属性列表
    };
    
    • Son
    static struct _class_ro_t _OBJC_CLASS_RO_$_Son = {
        0, __OFFSETOFIVAR__(struct Son, _age), sizeof(struct Son_IMPL), 
        (unsigned int)0, 
        0, 
        "Son",                                                              // 类名
        (const struct _method_list_t *)&_OBJC_$_INSTANCE_METHODS_Son,       // 方法列表
        0,                                                                  // 协议列表
        (const struct _ivar_list_t *)&_OBJC_$_INSTANCE_VARIABLES_Son,       // ivar列表
        0,                                                                  // weak修饰的ivar  
        0,                                                                  // 属性列表
    };
    

    2. _class_ro_T中的值

    在定义完结构体之后,我们在看看其中的成员方法列表,ivar列表,属性列表中分别都有什么:

    • Fathe

      • 成员方法列表

        static struct /*_method_list_t*/ {
            unsigned int entsize;  // sizeof(struct _objc_method)
            unsigned int method_count;
            struct _objc_method method_list[3];
        } _OBJC_$_INSTANCE_METHODS_Father = {
            sizeof(_objc_method),
            3,
            {{(struct objc_selector *)"initWithName:", "@24@0:8@16", (void *)_I_Father_initWithName_},
            {(struct objc_selector *)"name", "@16@0:8", (void *)_I_Father_name},
            {(struct objc_selector *)"setName:", "v24@0:8@16", (void *)_I_Father_setName_}}
        };
        

        Father里面有3个成员方法,其中namesetName:这两个方式是name属性的set和get方法,我们用@property修饰属性的时候,编译器会在编译的时候为我们生成相应的set和get方法

      • ivar成员变量列表

        static struct /*_ivar_list_t*/ {
            unsigned int entsize;  // sizeof(struct _prop_t)
            unsigned int count;
            struct _ivar_t ivar_list[1];
        } _OBJC_$_INSTANCE_VARIABLES_Father = {
            sizeof(_ivar_t),
            1,
            {{(unsigned long int *)&OBJC_IVAR_$_Father$_name, "_name", "@\"NSString\"", 3, 8}}
        };
        

        在Father里面,我们只用@property修饰器定义了一个成员属性,如果没有主动的定义_name成员变量的话,编译器会为我们主动生成_name这个成员变量。

      • 属性列表

        static struct /*_prop_list_t*/ {
            unsigned int entsize;  // sizeof(struct _prop_t)
            unsigned int count_of_properties;
            struct _prop_t prop_list[1];
        } _OBJC_$_PROP_LIST_Father = {
            sizeof(_prop_t),
            1,
            {{"name","T@\"NSString\",C,N,V_name"}}
        };
        

        可以看到,属性列表里面有我们定义的name

      Father的成员变量中的- (NSString *)name方法返回的是ivar列表中的_name成员变量,通过_name的偏移值来获取。

    • Son

      • 成员方法列表

        static struct /*_method_list_t*/ {
            unsigned int entsize;  // sizeof(struct _objc_method)
            unsigned int method_count;
            struct _objc_method method_list[1];
        } _OBJC_$_INSTANCE_METHODS_Son = {
            sizeof(_objc_method),
            1,
            {{(struct objc_selector *)"initWithName:age:", "@32@0:8@16Q24", (void *)_I_Son_initWithName_age_}}
        };
        

        Son里面只有1个成员方法和Father相比少了两个set和get方法

      • ivar成员变量列表

        static struct /*_ivar_list_t*/ {
            unsigned int entsize;  // sizeof(struct _prop_t)
            unsigned int count;
            struct _ivar_t ivar_list[1];
        } _OBJC_$_INSTANCE_VARIABLES_Son = {
            sizeof(_ivar_t),
            1,
            {{(unsigned long int *)&OBJC_IVAR_$_Son$_age, "_age", "Q", 3, 8}}
        };
        

        Son只有一个成员变量,因为代码中直接定义了这个_age成员变量

      Son中没有使用@property修饰器来定义一个属性,因此Son中的属性列表是空的。

    3. 设置_class_t的信息

    👆只是定义了类结构的信息,下面将对类结构的一些属性进行赋值

    • Father

      static void OBJC_CLASS_SETUP_$_Father(void ) {
        OBJC_METACLASS_$_Father.isa = &OBJC_METACLASS_$_NSObject;
        OBJC_METACLASS_$_Father.superclass = &OBJC_METACLASS_$_NSObject;
        OBJC_METACLASS_$_Father.cache = &_objc_empty_cache;
        OBJC_CLASS_$_Father.isa = &OBJC_METACLASS_$_Father;
        OBJC_CLASS_$_Father.superclass = &OBJC_CLASS_$_NSObject;
        OBJC_CLASS_$_Father.cache = &_objc_empty_cache;
      }
      

      这是对Father结构体进行赋值,这里面涉及到了OBJC_METACLASS_$_Father其实这是Fathermetaclass,将OBJC_CLASS_$_Fatherisa指针指向其metaclass,再将父类指针指向NSObject

    • Son

      static void OBJC_CLASS_SETUP_$_Son(void ) {
        OBJC_METACLASS_$_Son.isa = &OBJC_METACLASS_$_NSObject;
        OBJC_METACLASS_$_Son.superclass = &OBJC_METACLASS_$_Father;
        OBJC_METACLASS_$_Son.cache = &_objc_empty_cache;
        OBJC_CLASS_$_Son.isa = &OBJC_METACLASS_$_Son;
        OBJC_CLASS_$_Son.superclass = &OBJC_CLASS_$_Father;
        OBJC_CLASS_$_Son.cache = &_objc_empty_cache;
      }
      

      看起来和OBJC_METACLASS_$_Father好像没什么不一样的,但是其中将OBJC_CLASS_$_Son的父类设置成了OBJC_CLASS_$_Father并将其metaclass指向自己的OBJC_METACLASS_$_Son

    metaclass.jpg

    注意: OBJC_METACLASS_$_FatherOBJC_METACLASS_$_Son的isa指针都是指向OBJC_METACLASS_$_NSObject但是OBJC_METACLASS_$_Son的superclass指针是指向 OBJC_METACLASS_$_Father

    4. Metaclass

    既然提到了metaclass,那么我们接下来继续看一下FatherSon这两个类的metaclass分别长什么样的

    • Father

      struct _class_t OBJC_METACLASS_$_Father = {
        0, // &OBJC_METACLASS_$_NSObject,
        0, // &OBJC_METACLASS_$_NSObject,
        0, // (void *)&_objc_empty_cache,
        0, // unused, was (void *)&_objc_empty_vtable,
        &_OBJC_METACLASS_RO_$_Father,
      };
      

      OBJC_METACLASS_$_Father是一个_class_t结构体啊,再看看_OBJC_METACLASS_RO_$_Father

      static struct _class_ro_t _OBJC_METACLASS_RO_$_Father = {
        1, sizeof(struct _class_t), sizeof(struct _class_t), 
        (unsigned int)0, 
        0, 
        "Father",                                                       // metaclass名
        (const struct _method_list_t *)&_OBJC_$_CLASS_METHODS_Father,   // 方法列表
        0,                                                              // 协议列表
        0,                                                              // ivar成员变量列表
        0,                                                              // weak修饰的ivar
        0,                                                              // 属性列表
      };    
      

      Fathermetaclass里面只有方法列表有值

      static struct /*_method_list_t*/ {
        unsigned int entsize;  // sizeof(struct _objc_method)
        unsigned int method_count;
        struct _objc_method method_list[1];
      } _OBJC_$_CLASS_METHODS_Father = {
        sizeof(_objc_method),
        1,
        {{(struct objc_selector *)"fatherWithName:", "@24@0:8@16", (void *)_C_Father_fatherWithName_}}
      };
      

      OBJC_METACLASS_$_Father的方法列表里面一个方法,该方法是我们定义的便利构造器,说明一个类的类方法是放在类的metaclass中的。

    • Son

      struct _class_t OBJC_METACLASS_$_Son = {
        0, // &OBJC_METACLASS_$_NSObject,
        0, // &OBJC_METACLASS_$_Father,
        0, // (void *)&_objc_empty_cache,
        0, // unused, was (void *)&_objc_empty_vtable,
        &_OBJC_METACLASS_RO_$_Son,
      };
      
      static struct _class_ro_t _OBJC_METACLASS_RO_$_Son = {
        1, sizeof(struct _class_t), sizeof(struct _class_t), 
        (unsigned int)0, 
        0, 
        "Son",
        (const struct _method_list_t *)&_OBJC_$_CLASS_METHODS_Son,
        0, 
        0, 
        0, 
        0, 
      };
      
      static struct /*_method_list_t*/ {
        unsigned int entsize;  // sizeof(struct _objc_method)
        unsigned int method_count;
        struct _objc_method method_list[1];
      } _OBJC_$_CLASS_METHODS_Son = {
        sizeof(_objc_method),
        1,
        {{(struct objc_selector *)"sonWithName:age:", "@32@0:8@16Q24", (void *)_C_Son_sonWithName_age_}}
      };
      

      是的,Son的类方法也是定义在metaclass中的。

    第一次写,欢迎大牛提出意见,文中观点不太可靠,都是个人理解,不喜勿喷~~~

    相关文章

      网友评论

          本文标题:Objective-C类

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