从isa到类的结构分析

一、完善isa结构中shiftcls赋值时>>3原因

当将cls信息存储在shiftcls中时,默认会从起始位置开始存储(0位),由于isa结构中起始三位已经存在相应的存储含义,直接存储就不能完全将cls信息存储下来,所以右移三位,将shiftcls从起始位置就开始对应cls信息,这样才能完全存储。

截屏2020-09-12 下午8.00.31.png

二、isa与类的关系

isa流程图.png
  • 从上图isa虚线的走向可以看出,实例对象isa -> 元类 -> NSObject(根元类) -> 指向自身,验证如下
    截屏2020-09-12 下午8.50.14.png
  • 从isa流程图可以看出,类之间是继承关系,元类之间也是继承关系,而根元类(NSObject)自身就存在,没有父类,验证如下


    截屏2020-09-12 下午9.06.07.png
  • 注:实例对象之间不存在关系,只有类于类之间才混存在继承关系

三、类的结构分析 objc_object

截屏2020-09-12 下午9.13.56.png

从上面图中可以看出,objc_object中都有一个isa,因此可以验证每个对象中必定会包含isa

struct objc_class : objc_object {
    // Class ISA;  //只是用来解释此处毕竟包含一个isa,并不是一个注释
    Class superclass;
    cache_t cache;             //  占16  formerly cache pointer and vtable
    class_data_bits_t bits;    // class_rw_t * plus custom rr/alloc flags

上面代码只是粘贴了主要部分用来解释关键信息从第几位存储。
首先,objc_class继承与objc_object,因此objc_class

  • 首位必定是isa(8位),
  • superClass(8位),
struct cache_t {
#if CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_OUTLINED
    explicit_atomic<struct bucket_t *> _buckets;
    explicit_atomic<mask_t> _mask;
 #if __LP64__
    uint16_t _flags;
 #endif
    uint16_t _occupied;
    
// typedef unsigned short uint16_t; //2个字节
// typedef uint32_t mask_t; 
// typedef unsigned int uint32_t;//4个字节
// struct bucket_t {}//无属性,只有isa 8个字节
  • cache_t cache(本身是一个结构体根据属性去获取占用空间大小)
    • explicit_atomic<struct bucket_t *> _buckets(根据结构体去获取大小,无属性占8位),
    • uint16_t _flags;(2位)
    • uint16_t _occupied;(2位)

解析class_data_bits_t bits

bits中会存储大量的信息,如方法列表,属性等

截屏2020-09-12 下午10.10.24.png

*注:打印指针函数时使用-> 打印结构体的时候使用.

@interface LGPerson : NSObject
@property (nonatomic, strong)NSString * name;
- (void)sayHello;
+ (void)sayNo;
@end

截屏2020-09-12 下午10.10.52.png

从上图可以看出只有实例对象及实例方法,而LGPerson中声明的类方法没有打印出来,初步猜测是类方法在存储时是以实例方法进行存储的,并不能在此LGPerson的父类方法列表中读取。

总结

objc_object是所有类的原版,而其中包含isa属性,并且所有的对象中首对象都是isa

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