一、完善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
。