iOS程序猿iOS学习笔记iOS 开发每天分享优质文章

OC底层探索17 - 类的加载(上)

2021-06-24  本文已影响0人  Henry________

OC底层探索16 -应用程序加载中提到了dyld与objc的关系,主要是通过两个函数:map_imagesload_images来完成类的初始化。

一、 类的加载

1、从_objc_init入手

通过dyld调起libobjc库的初始化方法_objc_init,至此进入runtime的初始化流程

void _objc_init(void)
{
    //objc-环境变量初始化
    environ_init();
    //线程key的绑定
    tls_init();
    //C++函数提前执行
    static_init();
    //runtime的初始化
    runtime_init();
    //crash奔溃的处理
    exception_init();
#if __OBJC2__
    //缓存条件初始化
    cache_t::init();
#endif
    //特殊情况的回调处理
    _imp_implementationWithBlock_init();
    //map_images load_images注册到dyld中等待执行
    _dyld_objc_notify_register(&map_images, load_images, unmap_image);
}

2、map_images -> _read_images

注:此部分几个函数代码都很长,所以分几部分进行分析。

void map_images(unsigned count, const char * const paths[],
           const struct mach_header * const mhdrs[])
{
    return map_images_nolock(count, paths, mhdrs);
}

//代码很长,只放出核心代码
void map_images_nolock(unsigned mhCount, const char * const mhPaths[],
                  const struct mach_header * const mhdrs[])
{
    if (hCount > 0) {
        _read_images(hList, hCount, totalClasses, unoptimizedTotalClasses);
    }
}

void _read_images(header_info **hList, uint32_t hCount, int totalClasses, int unoptimizedTotalClasses)
{...}

2.1 readClass 类的标记

//代码很长,只放出核心代码
void _read_images(header_info **hList, uint32_t hCount, ...)
{
    //获取mach-o中所有的类
    classref_t const *classlist = _getObjc2ClassList(hi, &count);
    for (i = 0; i < count; i++) {
        Class cls = (Class)classlist[i];
        Class newCls = readClass(cls, headerIsBundle, headerIsPreoptimized);
    }
    // 标记所有类完成
    ts.log("IMAGE TIMES: discover classes");
    ...
}

Class readClass(Class cls, bool headerIsBundle, bool headerIsPreoptimized)
{
    //从mach-o里获取类名字符串
    const char *mangledName = cls->nonlazyMangledName();
    if (mangledName) {
        //将类名和类绑定存入HashMap中
        addNamedClass(cls, mangledName, replacing);
    } 
    //类加载到内存中了
    addClassTableEntry(cls);
    return cls;
}
2.1.1 addNamedClass
//将类名和类绑定后存入HashMap中
static void addNamedClass(Class cls, const char *name, Class replacing = nil)
{
   //插入到类与类名的映射表中
    NXMapInsert(gdb_objc_realized_classes, name, cls);
}
2.1.2 addClassTableEntry
//将类的信息加载到内存表中了
static void addClassTableEntry(Class cls, bool addMeta = true)
{
    auto &set = objc::allocatedClasses.get();
    //把类放入所有类的表中
    if (!isKnownClass(cls))
        set.insert(cls);
    //单次递归把元类也放入所有类的表中
    if (addMeta)
        addClassTableEntry(cls->ISA(), false);
}

2.2 非懒加载类data的加载

//代码很长,只放出核心代码
void _read_images(header_info **hList, uint32_t hCount, ...)
{
    //获取所有非懒加载类
    classref_t const *classlist = hi->nlclslist(&count);
    for (i = 0; i < count; i++) {
        //类的重定向
        Class cls = remapClass(classlist[i]);
        if (!cls) continue;
        realizeClassWithoutSwift(cls, nil);
    }
    ts.log("IMAGE TIMES: realize non-lazy classes");
}
2.2.1 非懒加载类懒加载类
IMP lookUpImpOrForward(id inst, SEL sel, Class cls, int behavior)
{
    checkIsKnownClass(cls);
    //该方法中完成类数据的加载和初始化
    cls = realizeAndInitializeIfNeeded_locked(inst, cls, behavior & LOOKUP_INITIALIZE);
    ...
}

static Class
realizeAndInitializeIfNeeded_locked(id inst, Class cls, bool initialize)
{
    //类若没有实现,则完成类的加载
    if (slowpath(!cls->isRealized())) {
        cls = realizeClassMaybeSwiftAndLeaveLocked(cls, runtimeLock);
    }
    //类没有初始化,则完成类的初始化
    if (slowpath(initialize && !cls->isInitialized())) {
        cls = initializeAndLeaveLocked(cls, inst, runtimeLock);
    }
    return cls;
}

2.2.2 realizeClassWithoutSwift类data的加载

static Class realizeClassWithoutSwift(Class cls, Class previously)
{
    // 从mach-o里获取类的data
    auto ro = (const class_ro_t *)cls->data();
    auto isMeta = ro->flags & RO_META;
    {
        // Normal class. Allocate writeable class data.
        //类data的设置
        rw = objc::zalloc<class_rw_t>();
        rw->set_ro(ro);
        rw->flags = RW_REALIZED|RW_REALIZING|isMeta;
        cls->setData(rw);
    }
#if FAST_CACHE_META
    //元类进行标记
    if (isMeta) cls->cache.setBit(FAST_CACHE_META);
#endif
    
    // 递归创建父类、元类
    supercls = realizeClassWithoutSwift(remapClass(cls->getSuperclass()), nil);
    metacls = realizeClassWithoutSwift(remapClass(cls->ISA()), nil);

    // Update superclass and metaclass in case of remapping
    // 建立父类、元类的关系
    cls->setSuperclass(supercls);
    cls->initClassIsa(metacls);

    // Set fastInstanceSize if it wasn't set already.
    // 类的子类在创建(alloc)中直接使用的大小在此处设置
    cls->setInstanceSize(ro->instanceSize);

    // Copy some flags from ro to rw
    //完成类的c++方法设置
    if (ro->flags & RO_HAS_CXX_STRUCTORS) {
        cls->setHasCxxDtor();
        if (! (ro->flags & RO_HAS_CXX_DTOR_ONLY)) {
            cls->setHasCxxCtor();
        }
    }
    // Connect this class to its superclass's subclass lists
    // 建立类双向链表关系
    if (supercls) {
        addSubclass(supercls, cls);
    } else {
        addRootClass(cls);
    }
    // 类中方法的加载
    methodizeClass(cls, previously);
    return cls;
}

2.3 类中方法的加载

static void methodizeClass(Class cls, Class previously)
{
    bool isMeta = cls->isMetaClass();
    auto rw = cls->data();
    auto ro = rw->ro();
    auto rwe = rw->ext();
    // Install methods and properties that the class implements itself.
    //获取类在mach-o的方法data
    method_list_t *list = ro->baseMethods();
    if (list) {
        //mach-o的方法data存在,则对方法SEL地址进行从小到大排序
        prepareMethodLists(cls, &list, 1, YES, isBundleClass(cls), nullptr);
        // 脏内存若存在直接完成方法的注入
        if (rwe) rwe->methods.attachLists(&list, 1);
    }
    property_list_t *proplist = ro->baseProperties;
    if (rwe && proplist) {
        //完成属性的注入
        rwe->properties.attachLists(&proplist, 1);
    }
    protocol_list_t *protolist = ro->baseProtocols;
    if (rwe && protolist) {
        //完成协议的注入
        rwe->protocols.attachLists(&protolist, 1);
    }
    //有分类的情况
    objc::unattachedCategories.attachToClass(cls, cls,
                                             isMeta ? ATTACH_METACLASS : ATTACH_CLASS);
}

2.3.1 attachLists中addedCount=1的情况

void attachLists(List* const * addedLists, uint32_t addedCount) {
    ...
    if (hasArray()) { // many lists -> many lists }
    else if (!list  &&  addedCount == 1) {
        // 0 lists -> 1 list
        list = addedLists[0];
    }
    else { // 1 list -> many lists }
    
}

总结

上一篇 下一篇

猜你喜欢

热点阅读