「这是我参与2022首次更文挑战的第5天,活动详情查看:2022首次更文挑战」。
前言
- 这篇主要内容探索 类与isa是如何关联的。
- 我们知道_class_createInstanceFromZone方法的关键三步:
a. 获取实例的内存空间大小: cls->instanceSize()
b. 根据内存大小,分配内存空间,让实例指向内存开始地址: calloc
c. 关联isa,实例的isa指向类: obj->initInstanceIsa(cls, hasCxxDtor), 结合位运算、联合体、位域和结构体的内存对齐的知识,我们探索oc对象的本质从关联isa,实例的isa指向类开始。
准备工作
先大概了解一个编译器:clang :
clang是一个由Apple主导编写,基于LLVM的C/C++/OC的编译器,主要是用于底层编译,将一些文件``输出成c++文件,例如main.m 输出成main.cpp;- 其目的是为了更好的观察底层的一些结构 及 实现的逻辑,方便理解底层原理。
一 、查看类的编译源码
1 .打开终端,cd到文件目录下,利用clang将main.m编译成 main.cpp .
**
//1、将 main.m 编译成 main.cpp
clang -rewrite-objc main.m -o main.cpp
其他举例:
//1、将 ViewController.m 编译成 ViewController.cpp
clang -rewrite-objc -fobjc-arc -fobjc-runtime=ios-13.0.0 -isysroot / /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator13.7.sdk ViewController.m
//以下两种方式是通过指定架构模式的命令行,使用xcode工具 xcrun
//2、模拟器文件编译
- xcrun -sdk iphonesimulator clang -arch arm64 -rewrite-objc main.m -o main-arm64.cpp
//3、真机文件编译
- xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main- arm64.cpp
2 .打开 main.cpp, 找到HJPerson,发现HJPerson在底层会被编译成 struct 结构体
点击NSObject_IMPL 跳转可以得到 isa
struct NSObject_IMPL {
Class isa;
};
先看这里:
struct HJPerson_IMPL {
struct NSObject_IMPL NSObject_IVARS;
NSString *_name;
};
这里的知识点:
HJPerson中的第一个属性NSObject_IVARS等效于NSObject中的isa, 每个类中都有默认属性isa;
二 、翻开objc源码 可以看到 NSObject的isa 也是class类型
@interface NSObject <NSObject> {
Class isa OBJC_ISA_AVAILABILITY;
}
现在我们通过clang 看到类被编译成结构体之后,找到isa ,那么isa是如何关联类的信息的呢?
我们可以在 _class_createInstanceFromZone 的核心方法的第三步:
关联isa,实例的isa指向类: obj->initInstanceIsa(cls, hasCxxDtor)中找到答案,这里做了一系列操作isa和类信息的操作,我们再去查看initInstanceIsa 内部源码
inline void
objc_object::initProtocolIsa(Class cls)
{
return initClassIsa(cls);
}
inline void
objc_object::initInstanceIsa(Class cls, bool hasCxxDtor)
{
ASSERT(!cls->instancesRequireRawIsa());
ASSERT(hasCxxDtor == cls->hasCxxDtor());
initIsa(cls, true, hasCxxDtor);
}
//排队
inline void
objc_object::initIsa(Class cls, bool nonpointer, bool hasCxxDtor)
{
//断言
ASSERT(!isTaggedPointer());
if (!nonpointer) {
//关键代码: 初始化isa
isa = isa_t((uintptr_t)cls);
} else {
//禁用非指针Isa
ASSERT(!DisableNonpointerIsa);
//实例需要原始Isa
ASSERT(!cls->instancesRequireRawIsa());
//关键代码: 初始化isa
isa_t newisa(0);
#if SUPPORT_INDEXED_ISA
ASSERT(cls->classArrayIndex() > 0);
newisa.bits = ISA_INDEX_MAGIC_VALUE;
// isa.magic是ISA_MAGIC_VALUE的一部分
// isa.nonpointer是ISA_MAGIC_VALUE的一部分
newisa.has_cxx_dtor = hasCxxDtor;
newisa.indexcls = (uintptr_t)cls->classArrayIndex();
#else
newisa.bits = ISA_MAGIC_VALUE;
newisa.has_cxx_dtor = hasCxxDtor;
newisa.shiftcls = (uintptr_t)cls >> 3;
#endif
isa = newisa;
}
}
重要代码:isa_t: 指针的初始化
isa = isa_t((uintptr_t)cls);isa_t newisa(0);
关键单词:nonpointer 非指针