知识点扩展
一: 位域
- 定义: 位域是一个==特殊类型的结构体==, 它会把xxx个字节中的二进位划分几个不同的区域, 并标识==每个区域的位数==, 每个域有一个域名, 允许在程序中按域名进行操作, 这样就可以把不同的对象用一个字节的二进制位域来表示.
// 位域
struct FixBitArea {
// 类型 域名 : 占据的位数
char front : 1;
char back : 1;
char left : 1;
char right : 1;
} fixBitArea;
@end
图1: 联合体位域二进位展示
- 优点: 内存使用更加精细灵活, 节省大量空间
因为我们在一些场景中, 是不需要那么大的空间, 比如说4个BOOL属性都分配4个字节, 那最后会占据128位空间(1字节=8位),但实际上,我们只需要1位就可以了. 运用union就可以很好的分配内存空间.
- 缺点: 各个变量直接是互斥的. 包容性会比较差.
2: union: 联合体
- 定义: 当多个数据需要共享内存或多个数据每次只取其一时, 可以利用==联合体(union)==
- 联合体是一个==结构==
- 它的所有成员相对于==内存起始位的偏移量都是0==
- 此结构内存空间需要大到==足够容纳内存最大的成员==
- 因为特点2共用一个首地址, 所以联合体中各成员是==互斥==的, 每次只能赋值一个成员, 赋入新值会冲掉旧值.
- 与结构体比较:
- 结构体每个成员是==依次存储== 而union中所有成员的==偏移位置均为0==
- 结构体内存的大小取决于==所有成员的内存大小, 以及字节对齐== 而union内存大小取决于所有成员中==内存最大==的内个
图2: struct与union内存分布对比
3: Clang:
- 定义: Clang是一个C语言, C++, OC语言的轻量级编译器(Clang是⼀个由Apple主导编写,基于LLVM的C/C++/Objective-C编译器).
- 常用命令:
1. 把⽬标⽂件编译成c++⽂件
clang -rewrite-objc main.m -o main.cpp
2. UIKit报错问题, 注意路径是否正确:
clang -rewrite-objc -fobjc-arc -fobjc-runtime=ios-13.0.0 -isysroot / Applications/Xcode.app/Contents/Developer/Platforms/ iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator13.0.sdk main.m
3. xcode安装的时候顺带安装了xcrun命令,xcrun命令在clang的基础上进⾏了⼀些封装,要更好⽤⼀些
xcrun -sdk iphonesimulator clang -arch arm64 -rewrite-objc main.m -o main-arm64.cpp (模拟器) xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o mainarm64.cpp (⼿机)
二: 看看什么是对象 -- > 探索isa结构体
-
回顾: 通过runtime源码, 还记得
obj->initInstanceIsa(cls, hasCxxDtor);的作用是关联内存指针和类, 今天我们顺着步骤来探索isa一路jump进去, 看到这个方法 图3: initIsa方法:
这里我们先注意以下方面, 之后的过程会分析:
- nonpointer: 详见截图注释
- isa的初始化和赋值(之所以ifelse分开, 是因为isa_t是一个联合体, 详见union: 联合体
- newisa.bits = ISA_MAGIC_VALUE;//纯isa指针时, 进行赋值
- newisa.shiftcls = (uintptr_t)cls >> 3;//这里保存的是类的信息
图4: 我们再来看isa_t的结构:
图5:ISA_BITFIELD位域信息:
- 这时候我们来看newisa.shiftcls = (uintptr_t)cls >> 3; 为什么要右移3位呢?
先查看isa_t联合体, 看到==ISA_BITFIELD==是一个占据64位的位域宏定义, 而shiftcls 占据3-35位, 所以存储的时候, 对于newisa.shiftcls来说 ,要节省内存 ,所以右移三位, 删除不需要的东西, 高位位置不够会自动删除, 只存储需要的信息,等用的时候, 再左移回去转换
**验证:
1: magci与宏定义验证(计算器)
2: isa shiftcls 验证