类的数据结构
clang 编译
clang -rewrite-objc main.m -o main.cpp 把⽬标⽂件编译成c++⽂件
xcrun -sdk iphonesimulator clang -arch x86_64 -rewrite-objc main.m
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m
clang -rewrite-objc main.m -o main.cpp 把⽬标⽂件编译成c++⽂件
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
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 main-arm64.cpp (⼿机)
- 将main.m 编译成 main.cpp 文件查看源码
- 拖至项目中并取消编译。运行
查看main.cpp文件
-
1.得到 LGPerson类,其实就是一个 LGPerson_IMPL 的结构体
-
2.struct NSObject_IMPL 也是一个结构体
- 3.结构体的继承
struct LGPerson_IMPL {
struct NSObject_IMPL NSObject_IVARS;
NSString *_KCName;
};
----------------------------------- 转化
struct LGPerson_IMPL {
Class isa;
NSString *_KCName;
};
复制代码
Class
- Class 是一个 objc_class * 的一个结构体指针
- id 是一个 objc_objct * 的一个结构体指针
- get 和 set
static NSString * _I_LGPerson_KCName(LGPerson * self, SEL _cmd) { return (*(NSString **)((char *)self + OBJC_IVAR_$_LGPerson$_KCName)); }
static void _I_LGPerson_setKCName_(LGPerson * self, SEL _cmd, NSString *KCName) { (*(NSString **)((char *)self + OBJC_IVAR_$_LGPerson$_KCName)) = KCName; }
self 和 _cmd 是隐藏参数,所以写一个方法时是默认自带了两个隐形参数,这就是为什么我们能在set和get以及其他的方法的作用域中可以直接写self.
get :
return (*(NSString **)((char *)self + OBJC_IVAR_$_LGPerson$_KCName));
self的指针首地址 + 地址偏移量获取值,包装成NSString * 返回
复制代码
联合体
- 结构体(struct)中所有变量是“共存”的——优点是“有容乃⼤”,
- 全⾯;缺点是struct内存空间的分配是粗放的,不管⽤不⽤,全分配。
- 联合体(union)中是各变量是“互斥”的——缺点就是不够“包容”;
- 但优点是内存使⽤更为精细灵活,也节省了内存空间
ISA 就是一个精细灵活的,也节约了内存空间。
- 要想学习Runtime,首先要了解它底层的一些常用数据结构,比如isa指针
- 在arm64架构之前,isa就是一个普通的指针,存储着Class、Meta-Class对象的内存地址
- 从arm64架构开始,对isa进行了优化,变成了一个共用体(union)结构,还使用位域来存储更多的信息
- 联合体(共同体)union是什么呢?
源码查看
- 找到这个isa 这个不是 class 而是一个isa_t
- 这个isa_t是一个union
- 具体定义在isa.h
- 这些应该就是架构了-不同的架构他的掩码也是不一样的位运算也是不一样的。
isa详解-位域
- nonpointer
- 0,代表普通的指针,存储着Class、Meta-Class对象的内存地址
- 1,代表优化过,使用位域存储更多的信息
- has_assoc
- 是否有设置过关联对象,如果没有,释放时会更快
- has_cxx_dtor
- 是否有C++的析构函数(.cxx_destruct),如果没有,释放时会更快
- shiftcls
- 存储着Class、Meta-Class对象的内存地址信息,在nonpointer=1的情况下,在arm64架构中有33位用来存储类指针 (重点)
- magic
- 用于在调试时分辨对象是否未完成初始化
- weakly_referenced
- 是否有被弱引用指向过,如果没有,释放时会更快。弱引用表。
- deallocating
- 对象是否正在释放
- extra_rc
- 里面存储的值是引用计数器减1
- has_sidetable_rc
- 引用计数器是否过大无法存储在isa中
- 如果为1,那么引用计数会存储在一个叫SideTable的类的属性中
- 所以结论就是要想真正知道类的信息其实找的不是isa,而是找isa中的 shiftcls,
- isa 左移三位,再右移20位 就可以获得shiftcls的数据。
- 补充