load 和 initialize

load ,initialize 有啥区别

调用方式的区别 : load 是根据函数地址直接调用initialize 是通过_objc_msgSend 调用
load 是runtime在加载类和分类的时候调用只会调用一次
initialize 是类第一次接收到消息的时候调用 每一个类只会 initialize 一次 但是父类会调用多次

load 是类在加载到内存的时候 被调用的 如果特别想在这个时候做什么可以调用
直入主题上代码
在这里插入图片描述
按照以往的调用顺序,category中的方法应该是在最先调用的才对。但是现在每一个类的load都有被调用这是为啥?

首先从 runtime初始化方法入手 runtime源码 objc-os.mm文件中 _objc_init()方法开始
在这里插入图片描述
load_images 加载镜像文件 ,通过名字可见 是要找的东西 jump进去

load_images(const char *path __unused, const struct mach_header *mh)
{
    // Return without taking locks if there are no +load methods here.
    if (!hasLoadMethods((const headerType *)mh)) return;

    recursive_mutex_locker_t lock(loadMethodLock);

    // Discover load methods
    {
        mutex_locker_t lock2(runtimeLock);
        prepare_load_methods((const headerType *)mh);
    }

    // Call +load methods (without runtimeLock - re-entrant)
    call_load_methods();
}

call_load_methods(); 调用 load 方法 进去看看
在这里插入图片描述
官方注释超级清楚

  • Call all pending class and category +load methods.
    调用所有class 和 category 的 +load 方法

  • Class +load methods are called superclass-first.
    类 的+load 方法 是超类 优先调用

  • Category +load methods are not called until after the parent class’s +load.
    category 的+load 方法 在类的 +load方法之后调用

  • Repeatedly call class +loads until there aren’t any more
    重复调用class +load,直到没有更多的

  • Call category +loads ONCE.
    调用类别+加载一次。

在看代码
loadable_classes_used

/***********************************************************************
* add_class_to_loadable_list
* Class cls has just become connected. Schedule it for +load if
* it implements a +load method.
**********************************************************************/
void add_class_to_loadable_list(Class cls)
{
    IMP method;

    loadMethodLock.assertLocked();

    method = cls->getLoadMethod();
    if (!method) return;  // Don't bother if cls has no +load method
    
    if (PrintLoading) {
        _objc_inform("LOAD: class '%s' scheduled for +load", 
                     cls->nameForLogging());
    }
    
    if (loadable_classes_used == loadable_classes_allocated) {
        loadable_classes_allocated = loadable_classes_allocated*2 + 16;
        loadable_classes = (struct loadable_class *)
            realloc(loadable_classes,
                              loadable_classes_allocated *
                              sizeof(struct loadable_class));
    }
    
    loadable_classes[loadable_classes_used].cls = cls;
    loadable_classes[loadable_classes_used].method = method;
    loadable_classes_used++;
}
`while (loadable_classes_used > 0) {
            call_class_loads();
 }` 如果有实现了 +(void)load 方法就会调用 call_class_loads()

jump进去
在这里插入图片描述
便利取出类里边的load方法,load_method 直接指向load方法的内存地址
typedef void(*load_method_t)(id, SEL);
直接指向函数地址
(*load_method)(cls, SEL_load);
然后调用


调用分类的load方法在这里插入图片描述
在这里插入图片描述

便利分类直接调用

为什么 load 三个都会调用,是因为 实现里,是通过遍历方法列表里的方法,直接拿到函数指针去调用函数 不是通过 objc_msgSend()调用(只要是通过发消息调用 就会产生顺序调用)

load调用顺序: 所有类的load 方法走完才走 分类的

类级别越高越先调用 平级的类 是通过编译顺序来控制 调用 load的顺序

分类的load 调用 不分先后 可以通过编译顺序来控制

编译顺序控制方法
在这里插入图片描述

+initialize

initialize 这个东西干啥的 我理解的就是 你特别想在这个类第一次使用的时候干些什么事 在你的类接收到消息之前会调用一个这个东西来初始化。也不知道对不对,实际开发中我没用过这个玩应。就连调用load 都屈指可数。

  • initialize方法会在类第一次接收到消息的时候调用

  • 如果有父类会点调用父类的 initialize 再调用子类的 initialize

虽然没用过但是也没准哪天就有人问 谁知道呢。

说一下我的查找思路,大致了解过runtime的 都说第一次接收消息都时候调用 也就是说应该从objc_msgSend开始查 但是这玩应是汇编写的,同时我又知道

  1. 当汇编在缓存查找方法 如果找到会直接Call
  2. CacheMiss 就会走到这里在这里插入图片描述
    在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZCwSC1z3-1581610990962)(media/15815699025453/15816099123398.jpg)]
然后发现了一个 initialize

return lookUpImpOrForward(cls, sel, obj, YES/*initialize*/, NO/*cache*/, YES/*resolver*/);

initialize 给传过来的是YES

 if (initialize  &&  !cls->isInitialized()) {
        runtimeLock.unlock();
        _class_initialize (_class_getNonMetaClass(cls, inst));
        runtimeLock.lock();
        // If sel == initialize, _class_initialize will send +initialize and 
        // then the messenger will send +initialize again after this 
        // procedure finishes. Of course, if this is not being called 
        // from the messenger then it won't happen. 2778172
    }

那这里就顺过来了。
if (YES && 类没有初始化){
_class_initialize (_class_getNonMetaClass(cls, inst));
调用初始化方法
}

在这里插入图片描述

supercls = cls->superclass;
    if (supercls  &&  !supercls->isInitialized()) {
        _class_initialize(supercls);
    }
    
    // Try to atomically set CLS_INITIALIZING.
    {
        monitor_locker_t lock(classInitLock);
        if (!cls->isInitialized() && !cls->isInitializing()) {
            cls->setInitializing();
            reallyInitialize = YES;
        }
    }
  1. 如果存在父类 并且父类没初始化 就去初始父类
  2. 父类初始化完继续执行然后吧自己也初始化

这是终极目标
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fvUFQAZG-1581610990962)(media/15815699025453/15816104213040.jpg)]

谨以此记录学习的点点滴滴

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值