Objective-C类

今天,我打算说说自己对于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中的。

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容