本系列博客是本人的源码阅读笔记,如果有 iOS 开发者在看 runtime 的,欢迎大家多多交流。
前言
继续我们的 _read_images 方法,_read_images 方法不愧是 runtime 中最重要的方法,它将所有的类相关的信息都读取出来,并做处理。今天我们要了解的就是新的这段代码:
for (EACH_HEADER) {
classref_t *classlist = _getObjc2NonlazyClassList(hi, &count);
for (i = 0; i < count; i++) {
Class cls = remapClass(classlist[i]);
if (!cls) continue;
realizeClass(cls);
}
}
这段代码很好理解,从 section 中获取类列表,并对每个 class 进行 remap 以及 realize 处理。但是大家肯定还有一些疑问,比如 :
- 方法 _getObjc2NonlazyClassList 作用是什么?
- realizeClass 看起来这么眼熟,那究竟是做什么的?
详细分析
NonlazyClass 介绍
NonlazyClass is all about a class implementing or not a +load method.
All the classes implemented in a given image file have a reference in a list stored in the "__DATA, __objc_classlist, regular, no_dead_strip" binary's section. This list allows the runtime system to keep track of all the classes stored in such file. However, not all of the classes need to be realized when the program starts up. That's why when a class implements
本文完整版详见笔者小专栏:https://xiaozhuanlan.com/runtime
那么,另外一个问题来了:
有多少 non-lazy class ?同样的,笔者写了如下代码,打印出所有的 non-lazy class :
// Realize non-lazy classes (for +load methods and static instances)
for (EACH_HEADER) {
classref_t *classlist =
_getObjc2NonlazyClassList(hi, &count);
for (i = 0; i < count; i++) {
Class cls = remapClass(classlist[i]);
//这里加了代码用于测试
printf("non-lazy Class:%s\n",cls->mangledName());
fflush(stdout);
if (!cls) continue;
realizeClass(cls);
}
}
打印的结果总结到笔者的GitHub了:non-lazy-classes.txt
可以看到,大概有60个 non-lazy-classes。
realizeClass 方法介绍
先看一下 realizeClass 方法的源代码:
static Class realizeClass(Class cls)
{
runtimeLock.assertWriting();
const class_ro_t *ro;
class_rw_t *rw;
Class supercls;
Class metacls;
bool isMeta;
if (!cls) return nil;
if (cls->isRealized()) return cls;
ro = (const class_ro_t *)cls->data();
if (ro->flags & RO_FUTURE) {
// This was a future class. rw data is already allocated.
rw = cls->data();
ro = cls->data()->ro;
cls->changeInfo(RW_REALIZED|RW_REALIZING, RW_FUTURE);
} else {
// Normal class. Allocate writeable class data.
rw = (class_rw_t *)calloc(sizeof(class_rw_t), 1);
rw->ro = ro;
rw->flags = RW_REALIZED|RW_REALIZING;
cls->setData(rw);
}
isMeta = ro->flags & RO_META;
rw->version = isMeta ? 7 : 0; // old runtime went up to 6
cls->chooseClassArrayIndex();
supercls = realizeClass(remapClass(cls->superclass));
metacls = realizeClass(remapClass(cls->ISA()));
cls->superclass = supercls;
cls->initClassIsa(metacls);
if (supercls && !isMeta) reconcileInstanceVariables(cls, supercls, ro);
cls->setInstanceSize(ro->instanceSize);
if (ro->flags & RO_HAS_CXX_STRUCTORS) {
cls->setHasCxxDtor();
if (! (ro->flags & RO_HAS_CXX_DTOR_ONLY)) {
cls->setHasCxxCtor();
}
}
if (supercls) {
addSubclass(supercls, cls);
} else {
addRootClass(cls);
}
methodizeClass(cls);
return cls;
}
以上代码比源代码简介一点,笔者移除了一些无关逻辑,方便大家理解。
上一篇文章我们已经做过一个 Demo,并得出一个结论:如果类中没有 +load 方法,那么 realize() 返回的就是 false,否则为空。并且另外的一些相关属性也会有所变化,比如:
- hasCxxCtor
- hasCustomAWZ
相信看了以上代码大家心里已经有了答案:
因为某个类中有 load 方法,该类就变成了 none-lazy class,而 none-lazy class 会提前实现 realizeClass 方法,后者会将里面的一些属性进行改变。比如调用 setHasCxxCtor 设置 hasCxxCtor 等。
总结
none-lazy class 是一个很特殊的区中取出来的 class 列表,至于苹果为什么这么设计,原因笔者估计就是为了提高效率:只有 load 方法实现的类中才提前设置它的一些属性,否则,只加载最基本的数据即可。