美文网首页
iOS底层--懒加载类/非懒加载类

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

作者: Engandend | 来源:发表于2020-04-29 00:38 被阅读0次

懒加载类和非懒加载类的区分很简单,就是看类有没有实现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方法

相关文章

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

    懒加载类和非懒加载类的区分很简单,就是看类有没有实现load方法 非懒加载类:在App启动时就开始对其进行实现,因...

  • OC底层原理14 - 类的加载之分类

    类的懒加载和非懒加载 在OC底层原理13 - 类的加载过程[https://www.jianshu.com/p/8...

  • iOS 类的加载分析 (中)

    非懒加载类和懒加载类 总纲领: OC底层探寻[https://www.jianshu.com/p/2fb69ff9...

  • 十二、类的加载

    懒加载类: 别人不动,我不动 非懒加载类: 通过+load 提前加载 我们可以到平时懒加载通过消息转发触发 ,所以...

  • iOS 懒加载类和非懒加载类

    一、非懒加载类 - 实现了类的load方法 1、我们知道在objc初始化代码 中间注册回调方法 map_image...

  • 底层原理:懒加载类与非懒加载类

    上一篇文章我们分析了dyld跟objc的关联中,已经研究到了_dyld_objc_notify_register中...

  • iOS底层原理19:类和分类的加载

    前面已经探究了类的加载流程,类分为懒加载类和非懒加载类,他们有不同加载流程,下面来探究下分类的加载,以及分类和类搭...

  • 类和分类的加载

    懒加载类和非懒加载类 在 类的加载 篇章里边 我们说了加载了类,分类,协议等等一些事情,注释我们可以看出来这里加载...

  • iOS---11---类和分类加载

    [toc] 类的加载 非懒加载类在运行时处理,懒加载编译期确定.区分:方式为load方法,把所有类的加载提前.看代...

  • iOS 类的加载(非懒加载类)

    在我们日常的开发中我们最常见的就是类,那么我们我们声明的类是如何被系统加载进来的呢?接下来我们就围绕着这个话题进行...

网友评论

      本文标题:iOS底层--懒加载类/非懒加载类

      本文链接:https://www.haomeiwen.com/subject/whxbwhtx.html