iOS-底层原理 04 类的结构分析(bits)

346

根据苹果官网给的关系图做了一些验证

isa流程图.png

1.查看同一个类在内存中的个数

    Class class1 = [HTPerson class];
    Class class2 = [HTPerson alloc].class;
    Class class3 = object_getClass([HTPerson alloc]);
    Class class4 = [HTPerson alloc].class;
    
    NSLog(@"\n%p-\n%p-\n%p-\n%p",class1,class2,class3,class4);

输出了如下的结果。证明同一个类在内存中,只会创建一个地址。

    0x100004990-   
    0x100004990-   
    0x100004990-   
    0x100004990   

2.查询类的isa地址指向

通过系统方法获取类的内存地址,以及使用lldb输出其内部结构

    // NSObject实例对象
    NSObject *object1 = [NSObject alloc];
    // NSObject类
    Class class = object_getClass(object1);
    // NSObject元类
    Class metaClass = object_getClass(class);
    // NSObject根元类
    Class rootMetaClass = object_getClass(metaClass);
    // NSObject根根元类
    Class rootRootMetaClass = object_getClass(rootMetaClass);
    
    NSLog(@"\n%p 实例对象\n%p 类\n%p 元类\n%p 根元类\n%p 根根元类",object1,class,metaClass,rootMetaClass,rootRootMetaClass);

输出了如下结果:

3B9E699C-0D46-4A9D-8DDC-007D9BBDA8A1.png

得出结论:

  • 实例对象的isa --> 类,
  • 类的isa --> 元类,
  • 元类对象isa --> 根元类
  • 根元类isa --> 根元类

3.类的继承关系

根据图中的继承关系(类-父类-父父类-null)做了如下验证:

    Class nSuperClass = class_getSuperclass(NSObject.class);//NSObject元类的父类
    
    NSLog(@"HTTeacher-类地址%p",HTTeacher.class);
    NSLog(@"HTPerson-父类地址%p",HTPerson.class);
    NSLog(@"NSObject-父父类地址%p",NSObject.class);
    NSLog(@"NSObjectSuper-父父父类%@ -- 父父父类%p",nSuperClass,nSuperClass);
    2021-06-20 18:34:30.592061+0800 002-isa分析[16955:397181] HTTeacher-类地址0x100008b40
    2021-06-20 18:34:30.592425+0800 002-isa分析[16955:397181] HTPerson-父类地址0x100008af0
    2021-06-20 18:34:30.592493+0800 002-isa分析[16955:397181] NSObject-父父类地址0x7fff94a3f118
    2021-06-20 18:34:30.592555+0800 002-isa分析[16955:397181] NSObjectSuper-父父父类(null) -- 父父父类0x0

证明HTPerson 继承于 NSObject,NSObject继承于nil

4.类的内部结构

查看源码如下

在源码objc.h中,可以看到 typedef struct objc_class *Class。class属于objc_class的指针类型。

  • 搜索 objc_class 可以找到如下三个成员:
struct objc_class : objc_object {
    ...
    // Class ISA;              //指向元类    8字节
    Class superclass;          //父类       8字节
    cache_t cache;             //缓存 结构体 16字节
    class_data_bits_t bits;    //对象方法和属性
    ...
   }
  • 查看 class_data_bits_t
struct class_data_bits_t {
   ...
     class_rw_t* data() const {
       return (class_rw_t *)(bits & FAST_DATA_MASK);
   }
   ...
}
  • 查看 class_rw_t里面有以下几个方法。
struct class_rw_t {
    //方法列表
    const method_array_t methods() const {...}
    //属性列表
    const property_array_t properties() const {...}
    //代理方法
    const protocol_array_t protocols() const {...}
}

5.根据内存地址中的存储内容进行验证:(使用到了内存地址平移

@interface LGPerson : NSObject{
    NSString *subject;
}
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *hobby;

- (void)sayNB;
+ (void)say666;

获取下面的输出结果:(x/4gx打印类的内存。p/x打印地址)

  • 获取属性列表

获取bits地址时需要进行字节平移,平移了32位。 0F080F0D-155E-42BB-B6BD-14E995D2761F.png

截屏2021-06-20 下午7.55.53.png

  • 获取实例方法(类似获取属性列表 properties改成-->methods()

截屏2021-06-20 下午7.59.41.png

  • 获取类的成员列表

截屏2021-06-22 下午5.12.24.png

  • 获取类方法列表(要去元类中去获取)

获取元类的地址 截屏2021-06-22 下午5.09.15.png 截屏2021-06-22 下午5.09.30.png

6.总结

类中有主要有isasuperclasscachebits成员变量,bits中存储属性列表、实例方法列表、成员变量列表、协议列表等. 其中类的类方法存储在元类的bits中。

搞完了,出去运动下。