iOS 类的加载过程

前言

在我们的程序的main函数执行前,系统给我们做了那些事儿,编译阶段:词法分析、语法分析、语义分析、生成中间代码IR 目标代码优化、生成汇编、然后连接器进行静态链接,把未绑定的符号进行绑定。运行阶段: dyld 动态链接将动态库进行绑定 例如System、UIKit、lidispatch,今天从_objc_init开始分析

  1. 方法调用链 最后会到_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);
  1. 开始加载类 关键方法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);
        }
    }
  1. 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) {
  1. 继续分析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);
    }
}
  1. 继续走 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 父类,将方法 属性 协议 类别这些东西都进行加载 保存在相应的位置,这样程序运行时才能顺利的调用到方法,属性等。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值