12、类的加载分析

2020-10-16  本文已影响0人  ChenL

上篇已经说明了 map_images,但没有详细说明,下面我们来继续..

1、_read_images分析

1、条件控制进行一次的加载
2、修复预编译阶段的 @selector的混乱问题
3、错误混乱的类处理
4、修复重映射一些没有被镜像文件加载进来的类
5、修复一些消息
6、当我们类里面有协议的时候:readProtocol
7、修复没有被加载的协议
8、分类处理
9、类的加载处理
10、没有被处理的类 优化那些侵犯的类

void _read_images(header_info **hList, uint32_t hCount, int totalClasses, int unoptimizedTotalClasses)
{
      里面的代码太多,就不一一说明了
}
// Discover classes. Fix up unresolved future classes. Mark bundle classes.
    bool hasDyldRoots = dyld_shared_cache_some_image_overridden();

    for (EACH_HEADER) {
        if (! mustReadClasses(hi, hasDyldRoots)) {
            // Image is sufficiently optimized that we need not call readClass()
            continue;
        }

        classref_t const *classlist = _getObjc2ClassList(hi, &count);

        bool headerIsBundle = hi->isBundle();
        bool headerIsPreoptimized = hi->hasPreoptimizedClasses();

       //确定类的继承关系
        for (i = 0; i < count; i++) {
            Class cls = (Class)classlist[i];
            Class newCls = readClass(cls, headerIsBundle, headerIsPreoptimized);

            if (newCls != cls  &&  newCls) {
                // Class was moved but not deleted. Currently this occurs 
                // only when the new class resolved a future class.
                // Non-lazily realize the class below.
                resolvedFutureClasses = (Class *)
                    realloc(resolvedFutureClasses, 
                            (resolvedFutureClassCount+1) * sizeof(Class));
                resolvedFutureClasses[resolvedFutureClassCount++] = newCls;
            }
        }
    }

2、readClass 分析

由上可以得到 cls 和 类名 关联起来..

image.png

增加条件判断--指定判断类

image.png
这个if语句肯定不会走的
    if (headerIsPreoptimized  &&  !replacing) {
        // class list built in shared cache
        // fixme strict assert doesn't work because of duplicates
        // ASSERT(cls == getClass(name));
        ASSERT(getClassExceptSomeSwift(mangledName));
    } else {

 那直接来到了这里了..
        addNamedClass(cls, mangledName, replacing);
        addClassTableEntry(cls);
    }

addNamedClass,给了cls名字

image.png

3、addNamedClass 方法分析

static void addNamedClass(Class cls, const char *name, Class replacing = nil)
{
    runtimeLock.assertLocked();
    Class old;
    if ((old = getClassExceptSomeSwift(name))  &&  old != replacing) {
        inform_duplicate(name, old, cls);

        // getMaybeUnrealizedNonMetaClass uses name lookups.
        // Classes not found by name lookup must be in the
        // secondary meta->nonmeta table.
        addNonMetaClass(cls);
    } else {
        NXMapInsert(gdb_objc_realized_classes, name, cls);
    }
    ASSERT(!(cls->data()->flags & RO_META));

    // wrong: constructed classes are already realized when they get here
    // ASSERT(!cls->isRealized());
}
image.png

走完NXMapInsert方法之后,这个类名就关联起来了~

二、懒加载类与非懒加载类

懒加载类与非懒加载类的区别:当前类是否实现load方法(load方法在mian函数之前)

1、非懒加载类情况

map_images的时候 加载所有类数据:

image.png

们也可以根据_read_images中的注释分析 ,当我们调试的时候没有走到这里,说明我们没有实现load,要是我们实现load的话是不是在这里就可以观察类的加载情况呢?

image.png image.png image.png

读取classdata数据,并将其强转为ro,以及rw初始化ro拷贝一份到rw中的ro

我们通过断点调试,发现他走的是 realizeClassWithoutSwift(cls, nil); (实现类)

image.png image.png

递归调用realizeClassWithoutSwift完善继承链,并设置当前类、父类、元类的rw
递归调用 realizeClassWithoutSwift设置父类元类
设置父类和元类的isa指向
通过addSubclassaddRootClass设置父子的双向链表指向关系,即父类中可以找到子类,子类中可以找到父类

image.png
2、懒加载类情况

数据加载推迟到第⼀次消息的时候

我们知道非懒加载怎么加的方法属性。那么懒加载呢?(把load去掉,然后调用一波),我们可以通过bt,或者 看堆栈

image.png

总结:

image.png
上一篇 下一篇

猜你喜欢

热点阅读