isa的作用与内部结构(下)

一、回顾

oc对象的本质的结构体,结构体内部存放了一个isa指针

//OC
@interface NSObject{
  Class isa; // 包含一个isa指针
}
// 对应的 C
struct NSObject_IMPL{
  Class isa;
}
// isa 本质就是一个指向 objc_class 结构体的指针
typedef struct objc_class *Class;
typedef struct objc_object *id; // id万能指针的原因
objc_class继承objc_object

二、源码分析

查看runtime源码发现 内部的isa是isa_t类型的

struct objc_object {
private:
    isa_t isa; // 此时的isa是isa_t类型的

public:
    // ISA() assumes this is NOT a tagged pointer object
    Class ISA();
    // getIsa() allows this to be a tagged pointer object
    Class getIsa();
    ......
}

isa的作用与内部结构(上)文中提到isa & 一个掩码值之后,才获取到真正的对象的地址,说明isa不是一个单纯的十六进制数据,isa_t类型的isa就是我们真正要找的isa的类型

isa_t的内部结构

union isa_t { //union共用体
    isa_t() { }
    isa_t(uintptr_t value) : bits(value) { }

    Class cls;
    uintptr_t bits;
#if defined(ISA_BITFIELD)
    struct {
        ISA_BITFIELD;  // defined in isa.h
    };
#endif
};

ISA_BITFIELD 内部定义了很多成员

#if SUPPORT_PACKED_ISA
// 真机
# if __arm64__
#   define ISA_MASK        0x0000000ffffffff8ULL
#   define ISA_MAGIC_MASK  0x000003f000000001ULL
#   define ISA_MAGIC_VALUE 0x000001a000000001ULL
#   define ISA_BITFIELD
      uintptr_t nonpointer        : 1;
      uintptr_t has_assoc         : 1;
      uintptr_t has_cxx_dtor      : 1;
      uintptr_t shiftcls          : 33;
      uintptr_t magic             : 6; 
      uintptr_t weakly_referenced : 1;
      uintptr_t deallocating      : 1;
      uintptr_t has_sidetable_rc  : 1;
      uintptr_t extra_rc          : 19
#   define RC_ONE   (1ULL<<45)
#   define RC_HALF  (1ULL<<18)
// 模拟器
# elif __x86_64__
#   define ISA_MASK        0x00007ffffffffff8ULL
#   define ISA_MAGIC_MASK  0x001f800000000001ULL
#   define ISA_MAGIC_VALUE 0x001d800000000001ULL
#   define ISA_BITFIELD
      uintptr_t nonpointer        : 1; 
      uintptr_t has_assoc         : 1;
      uintptr_t has_cxx_dtor      : 1;
      uintptr_t shiftcls          : 44;
      uintptr_t magic             : 6;
      uintptr_t weakly_referenced : 1;
      uintptr_t deallocating      : 1;
      uintptr_t has_sidetable_rc  : 1;
      uintptr_t extra_rc          : 8
#   define RC_ONE   (1ULL<<56)
#   define RC_HALF  (1ULL<<7)
# else
#   error unknown architecture for packed isa
# endif

整合到一起阅读

union isa_t { //union共用体
    isa_t() { }
    isa_t(uintptr_t value) : bits(value) { }
    Class cls;
    uintptr_t bits; // 用于存放所有的数据(struct中的变量)
    struct{
      uintptr_t nonpointer        : 1;
      uintptr_t has_assoc         : 1;
      uintptr_t has_cxx_dtor      : 1;
      uintptr_t shiftcls          : 33;
      uintptr_t magic             : 6; 
      uintptr_t weakly_referenced : 1;
      uintptr_t deallocating      : 1;
      uintptr_t has_sidetable_rc  : 1;
      uintptr_t extra_rc          : 19
    }
// nonpointer占1位、has_assoc占1位indexclas占15位
// 他们是按位计算,在内存中一个字节=8位
};

union 是c语言中的共用体,它和结构体有非常类似的用法

结构体和共用体的区别在于:结构体的各个成员会占用不同的内存,互相之间没有影响;而共用体的所有成员占用同一段内存,修改一个成员会影响其余所有成员。

获取共用体中的值可以通过位运算
按位与 & 同为1值为1,否则为0
按位或 | 同为1或1和0的时候,值为1,否则为0 
按位取反 ~ 1变为0,0变为1

 000111                                                                                                 
&111111          通过按位与的运算,我们可以获取特定位置的值 
-------
 000111

如 00110101,我们获取第三位是什么值
 00110101
&00000100              得出的结果为1
 00000100
由此可见,通过一个固定的掩码值,我们就可以获取到共用体内指定位置中的值。
//扩展定义,看源码的时候,会遇到这种情况
1<<0 表示将1向左移0位 000001 》000001
1<<1 表示将1向左移1位 000001 》000010
1<<2 表示将1向左移2位 000001 》000100

基本应用:如我们的控制器中有很多个BOOL变量的属性,我们就可以通过一个共用体来存放,获取不同值的时候,使用不同的掩码值,从而达到节省内存的作用
一个BOOL变零占4个字节,而在共用体内只占了1位,具体的使用不做细节描述,不是本文的 主要内容。抽时间专门写一篇文章作为补充

三、属性

// 获取内存地址
isa_t中 有一个shiftcls 长度为33位, 存放的就是地址 通过&一个掩码值,就可以获取shiftcls存放的值。

各个属性的作用

nonpointer : 
0,代表普通的指针,存储着Class、Meta-Class对象的内存地址 
1,代表优化过,使用位域存储更多的信息

has_assoc:是否有设置过关联对象,如果没有,释放时会更快
has_cxx_dtor:是否有C++的析构函数(.cxx_destruct),如果没有,释放时会更快
shiftcls:存储着Class、Meta-Class对象的内存地址信息
magic:用于在调试时分辨对象是否未完成初始化
weakly_referenced:是否有被弱引用指向过,如果没有,释放时会更快
deallocating:对象是否正在释放
has_sidetable_rc:引用计数器是否过大无法存储在isa中,如果为1,那么引用计数会存储在一个叫SideTable的类的属性中
extra_rc:里面存储的值是引用计数器减1

注意:对象的引用计数器是存储在isa中,extra_rc 占19位,最大数255,如果过大,就无法继续存储,extra_rc减半,另一部分就存放到一个叫SideTable的类中

四、总结

1.isa不是一个普通的指针,可以分为指针型isa和非指针型isa
2.指针型isa,isa的值代表Class的地址
3.非指针型isa,isa的部分值代表Class的地址
4.isa在内存是实际是 isa_t的一个共用体,内部存储着对象的很多信息

思考:isa指向的objc_class 是c/c++的结构体,它包含了NSObject对象的所有信息,objc_class 内部结构是什么样的?

isa的作用与内部结构(上)

你可能感兴趣的:(isa的作用与内部结构(下))