iOS底层--懒加载类/非懒加载类

2020-04-29  本文已影响0人  Engandend

懒加载类和非懒加载类的区分很简单,就是看类有没有实现load方法

非懒加载类:
在App启动时就开始对其进行实现,
因为这个类实现了load方法,load方法是在启动的时候就会被调用的,既然要调用方法,就需要对类进行实现,这个还是很好理解的

⚠️:还有2中情况会导致类即使不发送消息,也会提前实现
1、子类实现了load方法: 如果一个类(SuperA)有子类(ChildB),子类实现了load方法,那么这个类(SuperA)也可以认为是一个非懒加载类。
因为在进行类的加载的时候,SuperA 并不在非懒加载类的列表(下面的代码有打印非懒加载类列表),但是在进行ChildB初始化的时候,有一个递归加载,加载其父类,也就是说,在这个阶段SuperA也已经开始实现了
2、分类实现了load方法 在 这片文章的 2.1.2 部分讲了具体的实现流程

@interface JEPerson : NSObject
@end

@implementation JEPerson

+ (void)load
{
}
@end

非懒加载类
没有实现load方法,在第一次对其发送消息的时候(调用方法之前),才初始化
目的:降低启动的时间,减少启动工作量。比如一个项目中有10000个类,没有必要在启动的时候就全部加载出来,因为这个时候根本不需要用到它。

验证哪些类是非懒加载类?

_objc_init()
->
_dyld_objc_notify_register(&map_images, load_images, unmap_image);  中的map_images
->
map_images_nolock()
->
_read_images()
->
在 // Realize non-lazy classes (for +load methods and static instances)
下面的
for (i = 0; i < count; i++) {
    Class cls = remapClass(classlist[i]);
            
//添加这行代码  打印非懒加载类名
    printf("non-lazy classes: %s\n",cls->mangledName());  
            
    if (!cls) continue;
.....
}

创建几个类 并实现部分类的load方法 运行并查看打印

......
non-lazy classes: Protocol
non-lazy classes: __NSUnrecognizedTaggedPointer
non-lazy classes: NSObject            // 请注意:NSObject是一个非懒加载类
non-lazy classes: __NSArray0
......
non-lazy classes: NSConstantDate
non-lazy classes: __NSPlaceholderDictionary
non-lazy classes: NSConstantIntegerNumber
non-lazy classes: NSConstantFloatNumber
non-lazy classes: NSConstantDoubleNumber
non-lazy classes: NSApplication
non-lazy classes: NSBinder
non-lazy classes: NSColorSpaceColor
non-lazy classes: NSNextStepFrame
non-lazy classes: _DKEventQuery
non-lazy classes: JEStudent        ///<  这是实现了load方法的类

非懒加载类的初始化流程

还是进入read_images()的 非懒加载类的方法这里
Realize non-lazy classes (for +load methods and static instances) 里面的
realizeClassWithoutSwift()方法


static Class realizeClassWithoutSwift(Class cls, Class previously)
{

    ro = (const class_ro_t *)cls->data();
    if (ro->flags & RO_FUTURE) {        // 已经初始化过的类才会进入这里
     ...
    } else {
  // 第一次初始化类 创建一个新的rw  并对rw的ro赋值
        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;
#if FAST_CACHE_META
    if (isMeta) cls->cache.setBit(FAST_CACHE_META);
#endif
    rw->version = isMeta ? 7 : 0;  // old runtime went up to 6


    // Choose an index for this class.
    // Sets cls->instancesRequireRawIsa if indexes no more indexes are available
    cls->chooseClassArrayIndex();

//递归初始化父类和元类
    supercls = realizeClassWithoutSwift(remapClass(cls->superclass), nil);
    metacls = realizeClassWithoutSwift(remapClass(cls->ISA()), nil);
//.....  修改flags标记、关联父类、元类 等一系列操作
    return cls;
}

懒加载类的初始化流程

我们说懒加载类是在第一次发送消息(调用方法)的时候才初始化。
具体看看是怎样的流程。
在调用方法的时候 底层会首先找到 lookUpImpOrForward ()方法

怎么知道是调用这个方法呢?
方法一、底层源码看汇编 慢慢分析
方法二、汇编断点追踪 打开汇编模式(debug->always show disassembly) 在sendMsg call/jmp 通过in 进入查看,最终能看到 lookUpImpOrForward at objc-runtime-new.mm:5989

//创建一个  JEPerson类  并且没有实现load方法 并且没有子类
JEPerson *per = [JEPerson alloc];   //在这行打上断点

运行,来到这行断点之后,在 lookUpImpOrForward里面也打上断点

IMP lookUpImpOrForward(id inst, SEL sel, Class cls, int behavior)
{
❌❌
注意点:这里的cls 是元类,因为这里调用的是类方法 + (id)alloc
如何去验证?   
往下走,在`realizeClassWithoutSwift`方法中 有一个 isMeta的判断,那里为true
❌❌

.......
// 因为类还没有实现,所以会进入这个判断
  if (slowpath(!cls->isRealized())) {
        cls = realizeClassMaybeSwiftAndLeaveLocked(cls, runtimeLock);
    }

//如果类还没有初始化
if (slowpath((behavior & LOOKUP_INITIALIZE) && !cls->isInitialized())) {
        cls = initializeAndLeaveLocked(cls, inst, runtimeLock);
}
......
}

//继续追踪进去,
static Class
realizeClassMaybeSwiftMaybeRelock(Class cls, mutex_t& lock, bool leaveLocked)
{
.....
    if (!cls->isSwiftStable_ButAllowLegacyForNow()) {
        realizeClassWithoutSwift(cls, nil);
        if (!leaveLocked) lock.unlock();
    }
......
}

调用alloc方法之后的流程
lookUpImpOrForward()
-> realizeClassMaybeSwiftAndLeaveLocked() 传入的是元类,对元类进行实现
-> realizeClassWithoutSwift
->
出来之后 进入lookUpImpOrForward -> initializeAndLeaveLocked 对类进行初始化
->realizeClassWithoutSwift

简单点说:元类进行一次realizeClassWithoutSwift方法 之后 在对 类进行一次 realizeClassWithoutSwift方法

上一篇 下一篇

猜你喜欢

热点阅读