一、isa指针结构
- union isa_t
- {
- isa_t() { }
- isa_t(uintptr_t value) : bits(value) { }
- Class cls;
- uintptr_t bits;
- #if SUPPORT_PACKED_ISA
-
- // extra_rc must be the MSB-most field (so it matches carry/overflow flags)
- // nonpointer must be the LSB (fixme or get rid of it)
- // shiftcls must occupy the same bits that a real class pointer would
- // bits + RC_ONE is equivalent to extra_rc + 1
- // RC_HALF is the high bit of extra_rc (i.e. half of its range)
- // future expansion:
- // uintptr_t fast_rr : 1; // no r/r overrides
- // uintptr_t lock : 2; // lock for atomic property, @synch
- // uintptr_t extraBytes : 1; // allocated with extra bytes
- # if __arm64__
- # define ISA_MASK 0x0000000ffffffff8ULL
- # define ISA_MAGIC_MASK 0x000003f000000001ULL
- # define ISA_MAGIC_VALUE 0x000001a000000001ULL
- struct {
- uintptr_t nonpointer : 1;
- uintptr_t has_assoc : 1;
- uintptr_t has_cxx_dtor : 1;
- uintptr_t shiftcls : 33; // MACH_VM_MAX_ADDRESS 0x1000000000
- 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
- struct {
- uintptr_t nonpointer : 1;
- uintptr_t has_assoc : 1;
- uintptr_t has_cxx_dtor : 1;
- uintptr_t shiftcls : 44; // MACH_VM_MAX_ADDRESS 0x7fffffe00000
- 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
- // SUPPORT_PACKED_ISA
- #endif
-
-
- #if SUPPORT_INDEXED_ISA
- # if __ARM_ARCH_7K__ >= 2
- # define ISA_INDEX_IS_NPI 1
- # define ISA_INDEX_MASK 0x0001FFFC
- # define ISA_INDEX_SHIFT 2
- # define ISA_INDEX_BITS 15
- # define ISA_INDEX_COUNT (1 << ISA_INDEX_BITS)
- # define ISA_INDEX_MAGIC_MASK 0x001E0001
- # define ISA_INDEX_MAGIC_VALUE 0x001C0001
- struct {
- uintptr_t nonpointer : 1;
- uintptr_t has_assoc : 1;
- uintptr_t indexcls : 15;
- uintptr_t magic : 4;
- uintptr_t has_cxx_dtor : 1;
- uintptr_t weakly_referenced : 1;
- uintptr_t deallocating : 1;
- uintptr_t has_sidetable_rc : 1;
- uintptr_t extra_rc : 7;
- # define RC_ONE (1ULL<<25)
- # define RC_HALF (1ULL<<6)
- };
- # else
- # error unknown architecture for indexed isa
- # endif
- // SUPPORT_INDEXED_ISA
- #endif
- };
分析:
1.我们知道,实例对象的isa指针指向该对象所属类的类对象;类对象的isa指向其元类对象;
2.真机为arm64架构,模拟器和mac电脑为x86架架构,以下以arm64为例讲解;
3.在64位系统下,指针所占字节为8个即64位;
4.在arm64之前,isa就是一个普通的指针,存放着类(元类)对象的地址;之后,则需要&
ISA_MASK掩码,才能获取到类(元类)对象的地址,此时isa指针为一个共用体,存储的信息不局限于类(元类)对象的地址;
5.存储信息介绍:

其中,shiftcls结构体成员变量(33位)用来存储类(元类)对象的地址;
二、类(元类)对象的地址取值原理——位域
1.结构体支持位域运算
//代码
- struct bs {
- unsigned a : 9;//如果超过位域范围(511),则只取范围内的值,其他位(高位)丢弃
- unsigned b : 4;
- unsigned c : 3;
- }bit, *pbit;
- void test1()
- {
- bit.a = 512;//超过位域范围报警告
- bit.b = 10;
- bit.c = 7;
- NSLog(@"%d,%d,%d\n", bit.a, bit.b, bit.c);
-
- pbit=&bit;
- pbit-> a=0;
- pbit-> b&=3;
- pbit-> c|=1;
- printf("%d,%d,%d\n ",pbit-> a,pbit-> b,pbit-> c);
- }

//输出
- 2019-10-08 18:22:37.051464+0800 SetAndGetsForMask[1966:248996] 0,10,7
- 0,2,7
- Program ended with exit code: 0
//分析
1)unsigned即无符号整型,占4个字节;结构体中成员变量所占内存相互独立且连续;
2)以a为例,所占位数为9位即0b111111111(十进制511),所以a的取值范围0~511,如果是512(二进制0b1000000000),由于只取低9位(000000000),所以取出值为0;
3)按位与&:两个都为1运算结果为1,否则为0;按位或|:两个都为0运算结果为0,否则为1;
2.参照isa,共用体套用结构体,一个char字符(一个字节)存储多个BOOL值并制定存储位置
2.设置类属性BOOL值(setter and getter)
//Person
- #import "Person.h"
-
- //mask即掩码,表示二进制数(0b开头)
- #define TallMask (1<<0) //表示1左移0位:0b 0000 0001
- #define RichMask (1<<1) //表示1左移1位:0b 0000 0010
- #define HandsomeMask (1<<2) //表示1左移2位:0b 0000 0100
-
- //拓展:10<<3即在10对应的二进制数后添加3个0
-
- @interface Person()
- {
- char _saveBox;
- }
- @end
-
- @implementation Person
- - (instancetype)init
- {
- if (self = [super init]) {
- //用一个字节来存储三个变量:从最右往左依次为Tall、Rich、Handsome
- _saveBox = 0b00000101;
- }
- return self;
- }
- /*思路
- 0000 0101(_saveBox)
- |0000 0001(掩码)
- ---------
- 0000 0001(赋值tall为1)
-
- 0000 0101
- &1111 1110(掩码取反)
- ---------
- 0000 0100(赋值tall为0)
-
- 1.如果赋的值为1,则按位或;
- 2.如果赋的值为0,则掩码先取反,后按位与;
- */
- - (void)setTall:(BOOL)tall
- {
- if (tall) {
- _saveBox |= TallMask;
- } else {
- _saveBox &= ~TallMask;
- }
- }
- - (void)setRich:(BOOL)rich
- {
- if (rich) {
- _saveBox |= RichMask;
- } else {
- _saveBox &= ~RichMask;
- }
- }
- - (void)setHandsome:(BOOL)handsome
- {
- if (handsome) {
- _saveBox |= HandsomeMask;
- } else {
- _saveBox &= ~HandsomeMask;
- }
- }
- /*思路
- 0000 0101
- &0000 0001
- ---------
- 0000 0001(取出tall值)
-
- 1.按位与,用掩码取出_saveBox中特定位;
- 2.结果>=1,取反为0,再取反为1;同理,为0则双取反后为0;
- */
- - (BOOL)isTall
- {
- return !!(_saveBox & TallMask);
- }
- - (BOOL)isRich
- {
- return !!(_saveBox & RichMask);
- }
- - (BOOL)isHandsome
- {
- return !!(_saveBox & HandsomeMask);
- }
- @end
//Student
- #import "Student.h"
-
- @interface Student()
- {
- /*思路
- 1.用一个结构体来存放变量;
- 2.结构体支持位域:按先后顺序,一个char字符一个字节(0b0000 0000),从最右至左依次为tall、rich、handsome;
- */
- struct {
- char tall : 1;//用一位来存储
- char rich : 1;
- char handsome : 1;
- }_tallRichHandsome;
- }
- @end
-
- @implementation Student
- - (void)setTall:(BOOL)tall
- {
- _tallRichHandsome.tall = tall;
- }
- - (void)setRich:(BOOL)rich
- {
- _tallRichHandsome.rich = rich;
- }
- - (void)setHandsome:(BOOL)handsome
- {
- _tallRichHandsome.handsome = handsome;
- }
- - (BOOL)isTall
- {
- return !!_tallRichHandsome.tall;//非0(包括负数)取反为0
- }
- - (BOOL)isRich
- {
- return !!_tallRichHandsome.rich;
- }
- - (BOOL)isHandsome
- {
- return !!_tallRichHandsome.handsome;
- }
- @end
//Worker
- #import "Worker.h"
-
- #define TallMask (1<<0)//也可以左移6位,剩余位没用到
- #define RichMask (1<<1)
- #define HandsomeMask (1<<2)
- #define ThinMask (1<<3)
-
- @interface Worker()
- {
- //苹果系统设计思路
- union {
- char bits;//一个字节存储结构体中的所有成员变量
- struct {//摆设用:位域,增加可读性
- char tall : 1;//占一位
- char rich : 1;
- char handsome : 1;
- char thin : 1;
- };
- }_tallRichHandsome;
- }
- @end
-
- @implementation Worker
- - (void)setTall:(BOOL)tall
- {
- if (tall) {
- NSLog(@"----%c", _tallRichHandsome.bits);
- _tallRichHandsome.bits |= TallMask;
- } else {
- _tallRichHandsome.bits &= ~TallMask;
- }
- }
- - (void)setRich:(BOOL)rich
- {
- if (rich) {
- _tallRichHandsome.bits |= RichMask;
- } else {
- _tallRichHandsome.bits &= ~RichMask;
- }
- }
- - (void)setHandsome:(BOOL)handsome
- {
- if (handsome) {
- _tallRichHandsome.bits |= HandsomeMask;
- } else {
- _tallRichHandsome.bits &= ~HandsomeMask;
- }
- }
- - (void)setThin:(BOOL)thin
- {
- if (thin) {
- _tallRichHandsome.bits |= ThinMask;
- } else {
- _tallRichHandsome.bits &= ~ThinMask;
- }
- }
- - (BOOL)isTall
- {
- return !!(_tallRichHandsome.bits & TallMask);
- }
- - (BOOL)isRich
- {
- return !!(_tallRichHandsome.bits & RichMask);
- }
- - (BOOL)isHandsome
- {
- return !!(_tallRichHandsome.bits & HandsomeMask);
- }
- - (BOOL)isThin
- {
- return !!(_tallRichHandsome.bits & ThinMask);
- }
- @end
//main
- #import <Foundation/Foundation.h>
- #import "Person.h"
- #import "Student.h"
- #import "Worker.h"
- #import "Engineer.h"
-
- struct bs {
- unsigned a : 9;//如果超过位域范围(511),则只取范围内的值,其他位(高位)丢弃
- unsigned b : 4;
- unsigned c : 3;
- }bit, *pbit;
- void test1()
- {
- bit.a = 512;//超过位域范围报警告
- bit.b = 10;
- bit.c = 7;
- NSLog(@"%d,%d,%d\n", bit.a, bit.b, bit.c);
-
- pbit=&bit;
- pbit-> a=0;
- pbit-> b&=3;
- pbit-> c|=1;
- printf("%d,%d,%d\n ",pbit-> a,pbit-> b,pbit-> c);
- }
- void test2()
- {
- Person *per = [[Person alloc] init];
- per.tall = NO;
- per.rich = NO;
- per.handsome = YES;
- NSLog(@"%d %d %d", per.isTall, per.isRich, per.isHandsome);
- }
- void test3()
- {
- Student *stu = [[Student alloc] init];
- stu.tall = YES;
- stu.rich = NO;
- stu.handsome = YES;
- NSLog(@"%d %d %d", stu.isTall, stu.isRich, stu.isHandsome);
- }
- void test4()
- {
- Worker *worker = [[Worker alloc] init];
- // worker.tall = YES;
- worker.rich = NO;
- worker.handsome = NO;
- worker.thin = YES;
- NSLog(@"%d %d %d", worker.isThin, worker.isRich, worker.isHandsome);
- }
- void test5()
- {
- Engineer *engineer = [[Engineer alloc] init];
- // engineer.age = 12;
- // engineer.level = 6;
- // engineer.workers = 5;
-
- //0b 1111 1111 1111 1111(十进制:65535)
- //0b 0010 1100 1110 1101(十进制:11501)
- engineer->_personalInfo.bits =11501;
- NSLog(@"%d %d %d", engineer.getAge, engineer.getLevel, engineer.getWorkers);
- //2019-10-08 16:42:09.612140+0800 SetAndGetsForMask[1488:127227] 7 16 8160
- //
- }
- int main(int argc, const char * argv[]) {
- @autoreleasepool {
-
- test1();
- // test2();
- // test3();
- // test4();
- // test5();
- }
- return 0;
- }
//打印
- 2019-10-09 10:42:04.998750+0800 SetAndGetsForMask[2513:316066] 0 0 1
- 2019-10-09 10:42:04.999093+0800 SetAndGetsForMask[2513:316066] 1 0 1
- 2019-10-09 10:42:04.999122+0800 SetAndGetsForMask[2513:316066] 1 0 0
- Program ended with exit code: 0
//分析(以Worker为例)
1)共用体中所有成员共同占用一块内存区,其大小等于最大那个成员所占字节数;
2)Worker中的结构体并为定义变量,编译器不会计算其内存,仅是增加可读性;
3)Worker中只有一个char型变量bits(占一个字节),故该共用体变量_tallRichHandsome也占一个字节;
4)结构体的位域限制变量的取值范围(一位:即0或1),mask掩码规定该变量存储的位置(在哪一位上);
3.设置类属性非BOOL类型(setter and getter)——限定变量值范围且指定存储位置
//Engineer
- #import <Foundation/Foundation.h>
- NS_ASSUME_NONNULL_BEGIN
- //位域位置(变量值存储位置)
- #define AgeMask 0b00000111//最低三位存储
- #define LevelMask (1<<4)//低位往高位数,第5位存储
- #define WorkersMask 0b0001111111100000
-
- @interface Engineer : NSObject
- {
- @public
- union {
- int bits;
- struct {//位域范围(变量值范围)
- int age : 3;
- int level : 1;
- int workers : 8;
- };
- }_personalInfo;
- }
- //- (void)setAge:(int)age;
- //- (void)setLevel:(int)level;
- //- (void)setWorkers:(int)workers;
-
- - (int)getAge;
- - (int)getLevel;
- - (int)getWorkers;
- @end
- NS_ASSUME_NONNULL_END
- #import "Engineer.h"
-
- @implementation Engineer
- //- (void)setAge:(int)age
- //{
- // self->_personalInfo.bits |= AgeMask;
- //}
- //
- //- (void)setLevel:(int)level
- //{
- // self->_personalInfo.bits |= LevelMask;
- //}
- //
- //- (void)setWorkers:(int)workers
- //{
- // self->_personalInfo.bits |= WorkersMask;
- //}
-
- - (int)getAge
- {
- return self->_personalInfo.bits & AgeMask;
- }
- - (int)getLevel
- {
- return self->_personalInfo.bits & LevelMask;
- }
- - (int)getWorkers
- {
- return self->_personalInfo.bits & WorkersMask;
- }
- @end
//打印
- 2019-10-09 11:08:14.617655+0800 SetAndGetsForMask[2630:349068] 5 0 3296
- Program ended with exit code: 0
//说明
1)掩码mask既可以直接用二进制(0b开头)或十六进制(0x开头)表示,也可以左移符号<<表示(一般用于位域为1的情况);
2)掩码表示所占位数:1表示占住该位,0未占;并且所占位数应当是连续的,不存在两侧为1,中间为0的情况;
三、结论
1.arm64之后,isa是一个共用体类型的指针,存储内部套用的结构体中的所有成员变量;
2.根据结构体的位域来限制成员变量的值范围,用掩码来规定成员变量存储的位置,对掩码按位与运算取出特定位置的成员变量的值;
如:用bits对ISA_MASK按位与运算后,得到的是类(元类)对象的地址;

可以看到shiftcls成员变量位域为33位,所占bits变量的存储位置为:地位到高位第四位起,最低三位是空出来的
————因此,在arm64架构中,所有的类和元类对象地址二进制表示时最低三位都为0,十六进制表示时最低一位为0或8(这个用class和object_getClass去打印地址,此处不再展示了)!
GitHub