isa 和 联合体位域的理解
isa
之前说过 实例对象isa 指向类对象 类的isa 指向 元类对象
但是要 & 一个 ISA_MASK
// ISA()方法用于返回类指针
inline Class
objc_object::ISA()
{
assert(!isTaggedPointer());
#if SUPPORT_INDEXED_ISA
if (isa.nonpointer) {
uintptr_t slot = isa.indexcls;
return classForIndex((unsigned)slot);
}
return (Class)isa.bits;
#else
// ISA_MASK的值是0x00007ffffffffff8ULL
// 通过按位与的方式获取到类指针,ISA_MASK中对应的isa.bits中类指针的位数,均为1
return (Class)(isa.bits & ISA_MASK);
#endif
}
# if __arm64__
# define ISA_MASK 0x0000000ffffffff8ULL
# elif __x86_64__
# define ISA_MASK 0x00007ffffffffff8ULL
为什么要 & ISA_MASK
isa_t 结构体
- arm64 位之后 isa变成了一个 结构体位域 NONPOINTER_ISA 现在的isa 基本上都是被优化过的isa
NONPOINTER_ISA 苹果将 isa 设计成了联合体,在 isa 中存储了与该对象相关的一些内存的信息,但是并不需要 64 个二进制位全部都用来存储指针 因为浪费空间 所以做了优化。
位域 的操作
-
& 操作 与
0000 0011
0000 0010 = 0010 也就是两组数 两个都是 1 就返回1否则返回 0( 如果想把某一位设值成0 只要把那一位 设置成0 其他的全设置成 1 然后做一个 & 操作 比如 0010 1010 想把第二位改为0 也就是 0010 1000 也就是
0010 1010 & 1111 1101 ----- 两组数都是1 就返回1 有一个0 就是0 ) -
| 操作 或
0000 0010
0000 0011 = 0011 两组数只要有一个是1 那就是 1 否则返回0
为了更清楚的了解原理使用这种写法看得更清楚
查看地址 x 第一个字节 05
0000 0101 == 05
接下来说说为什么明明是1 但是log 却是 -1
aaa bbb ccc 现在设定的分别是 1位二进制位 而一个BOOL 是占一个字节8位 需要补位 全部都补1 就变成了 0b11111111
0xff 有符号就是-1 无符号就是255
只要把 aaa bbb ccc 都设置成两位 就可以解决这个问题 只要有一个0 和前面的1 分隔
公用体:大家公用一块内存
union{
char bits; //1个字节
struct { //这个结构体里的内容和 bits 公用同一块内存 1个字节8位 写不谢都行为了可读性
char aaa : 1;
char bbb : 1;
char ccc : 1;
};
}_ppp;
#define aaaMask (0b1111<<0) // 0000 0000 0000 0000 0000 0000 0000 1111 4位 4位的改
#define bbbMask (0b1111<<4) // 0000 0000 0000 0000 0000 0000 1111 0000
#define cccMask (0b1111<<8) // 0000 0000 0000 0000 0000 1111 0000 0000
或者可以写成 1111 == 15
#define aaaMask (15<<0) // 0000 0000 0000 0000 0000 0000 0000 1111 4位 4位的改
#define bbbMask (15<<4) // 0000 0000 0000 0000 0000 0000 1111 0000
#define cccMask (15<<8) // 0000 0000 0000 0000 0000 1111 0000 0000
@interface Person ()
{
union{
int bits;
struct {
char aaa : 4;
char bbb : 4;
char ccc : 4;
};
}_ppp;
}
@end
类的指针为什么 & ISA_MASK :
uintptr_t shiftcls : 33; /*MACH_VM_MAX_ADDRESS 0x1000000000*/ \
实例对象isa 指向类对象 类的isa 指向 元类对象 isa
前面有三位表示
1.指针类型
2.关联对象
3.c++析构函数
前三位代表其他的东西 不是我们需要的 我们要找的是那33 位
用33 + 3 也就是36的位置 可见全是1
也就是我们需要的 33位 & 33 个 1 可以得出这33 位的真值
位域 的实际使用
#import "ViewController.h"
//typedef enum {
// DenumOne = 1, //0b0001
// DenumTwo = 2, //0b0010
// DenumThree = 4, //0b0100
// DenumFour = 8, //0b1000
//}Denums;
typedef enum {
DenumOne = (1<<0), //0b0001
DenumTwo = (1<<1), //0b0010
DenumThree = (1<<2), //0b0100
DenumFour = (1<<3), //0b1000
}Denums;
@interface ViewController ()
@end
@implementation ViewController
// | 运算 有一个是1 返回值就是1
// 0b0001 |
// 0b0010 |
// 0b0100 |
//--------------
// 0b0111
// 这和求和是一样的
//如果用 0b0111 和 DenumOne 0b0001 做 & 操作得到的结果
// 0b0111 0b0111 0b0111
// 0b0001 0b0010 0b1000
//------------------------------ & 操作 两个都是1 才返回1 否则返回0 用总和 和自身做&操作 还是自己
// 0b0001 0b0010 0b0000 总和 和 0b1000做 &操作 就都是0
- (void)setDenum:(Denums)enums
{
if (enums & DenumOne) {
NSLog(@"有1");
}
if (enums & DenumTwo) {
NSLog(@"有2");
}
if (enums & DenumThree) {
NSLog(@"有3");
}
if (enums & DenumFour) {
NSLog(@"有1");
}
}
- (void)viewDidLoad {
[super viewDidLoad];
[self setDenum:DenumOne | DenumTwo | DenumThree];
}
2020-02-18 13:30:24.513855+0800 blockTest[25965:10829655] 有1
2020-02-18 13:30:24.513967+0800 blockTest[25965:10829655] 有2
2020-02-18 13:30:24.514094+0800 blockTest[25965:10829655] 有3