前言
在我们的程序的main函数执行前,系统给我们做了那些事儿,编译阶段:词法分析、语法分析、语义分析、生成中间代码IR 目标代码优化、生成汇编、然后连接器进行静态链接,把未绑定的符号进行绑定。运行阶段: dyld 动态链接将动态库进行绑定 例如System、UIKit、lidispatch,今天从_objc_init开始分析
- 方法调用链 最后会到_read_images
_dyld_objc_notify_register(&map_images, load_images, unmap_image);
map_images(unsigned count, const char * const paths[],
const struct mach_header * const mhdrs[]).
map_images_nolock(unsigned mhCount, const char * const mhPaths[],
const struct mach_header * const mhdrs[]).
最终会来到 _read_images(hList, hCount, totalClasses, unoptimizedTotalClasses);
- 开始加载类 关键方法Class newCls = readClass(cls, headerIsBundle, headerIsPreoptimized);
for (EACH_HEADER) {
classref_t *classlist = _getObjc2ClassList(hi, &count);
bool headerIsBundle = hi->isBundle();
bool headerIsPreoptimized = hi->isPreoptimized();
for (i = 0; i < count; i++) {
Class cls = (Class)classlist[i];
Class newCls = readClass(cls, headerIsBundle, headerIsPreoptimized);
}
}
- readClass 关键源码
Class readClass(Class cls, bool headerIsBundle, bool headerIsPreoptimized)
{
addNamedClass(cls, mangledName, replacing);
addClassTableEntry(cls);
}
从上边两个方法的注释来看 addNamedClass 是加载共享缓存中的类 插入表 addClassTableEntry加载我们所有自己的类
static void addNamedClass(Class cls, const char *name, Class replacing = nil)
{
NXMapInsert(gdb_objc_realized_classes, name, cls);
}
// This is a misnomer: gdb_objc_realized_classes is actually a list of
// named classes not in the dyld shared cache, whether realized or not.
NXMapTable *gdb_objc_realized_classes;
* Add a class to the table of all classes. If addMeta is true,
* automatically adds the metaclass of the class as well.
static void addClassTableEntry(Class cls, bool addMeta = true) {
- 继续分析realizeClassWithoutSwift 关键源码
static Class realizeClassWithoutSwift(Class cls)
{
// 给 ro赋值 ro中存储的 属性 方法 协议 等
rw = (class_rw_t *)calloc(sizeof(class_rw_t), 1);
rw->ro = ro;
rw->flags = RW_REALIZED|RW_REALIZING;
cls->setData(rw)
// 实现元类和父类
supercls = realizeClassWithoutSwift(remapClass(cls->superclass));
metacls = realizeClassWithoutSwift(remapClass(cls->ISA()));
// 将父类和元类给我们的类 分别是isa和父类的对应值
cls->superclass = supercls;
cls->initClassIsa(metacls);
// 双向链表指向关系 父类中可以找到子类 子类中也可以找到父类
if (supercls) {
addSubclass(supercls, cls);
} else {
addRootClass(cls);
}
}
- 继续走 methodizeClass 源码简直太有意思了 此时给rw赋值 一直纳闷的问题 ro中也有方法列表 rw中也有方法列表,在这段源码中解释的很清楚
static void methodizeClass(Class cls)
{
bool isMeta = cls->isMetaClass();
auto rw = cls->data(); // 初始化一个rw
auto ro = rw->ro;
// 将ro中的方法列表加入到rw中
method_list_t *list = ro->baseMethods();
if (list) {
prepareMethodLists(cls, &list, 1, YES, isBundleClass(cls));
rw->methods.attachLists(&list, 1);
}
// 加入属性
property_list_t *proplist = ro->baseProperties;
if (proplist) {
rw->properties.attachLists(&proplist, 1);
}
// 加入协议
protocol_list_t *protolist = ro->baseProtocols;
if (protolist) {
rw->protocols.attachLists(&protolist, 1);
}
// 加入类别中的方法
category_list *cats = unattachedCategoriesForClass(cls, true /*realizing*/);
attachCategories(cls, cats, false /*don't flush caches*/);
}
也就是说 rw中会包含动态创建的方法 >= ro中的方法。
总结
iOS中的可执行文件是machO文件, 程序运行前会加载镜像文件,实现我们的类,主要就是加载共享缓存中的类,加载我们自己创建的类,初始化类的isa 父类,将方法 属性 协议 类别这些东西都进行加载 保存在相应的位置,这样程序运行时才能顺利的调用到方法,属性等。