美文网首页
load 和 initialize

load 和 initialize

作者: 张_何 | 来源:发表于2020-04-11 22:39 被阅读0次

    load

    • +load 方法会在 runtime 加载类、分类是调用,每个类、分类的 load 方法,在程序运行过程中只调用一次。
    • 调用顺序:
      1.先调用类的load 方法,按照编译的先后顺序调用(先编译先调用),调用子类的load之前会先调用父类的 load方法
      2.再调用分类的 load 方法,哪找编译的先后顺序调用(先编译先调用)
    • load 方法可以继承,但一般不手动调用,而是让系统调用,系统会在加载类的时候调用,这个时候是直接找到类的 load 方法调用;如果手动调用的话,会走消息机制调用。
    load 函数调用解析

    在运行时加载程序时会调用call_load_methods()函数

    void call_load_methods(void) {
      ....
      do{
            while(loadable_classes_used > 0) {
                  call_class_loads(); //调用类的+load 方法
            }
            more_categories = call_category_loads(); //调用分类的 +load 方法
      } while (loadable_classes_used > 0 || more_categories);
      ...
    }
    

    根据以上代码我们可以知道,先调用类的 load方法,类的 load方法调用完才会调用分类的load方法。那么这里为什么跟我们OC 的消息机制不一样呢?oc 的消息机制不是去方法列表里面去找,找到后直接调用吗?如果按照 OC 的消息机制先找到的应该是分类中的方法,应该调用分类的方法才正确呀!其实这里主要是因为load方法并不是走 OC 的消息机制,而是通过类找到load方法直接调用的。分类的load 方法也是直接找通过分类找到load方法然后直接调用的

    // 类的 load 方法调用
    for (i = 0; i < used; i++) { 
      Class cls =classes[i].cls;
      load_method_ t load_method = (load_method_t)classes[i].method; //取出类的 load 方法直接调用。这里 method 就是指向 load 方法。
    ....
    }
    // 分类的 load 方法调用
    for (i = 0; i < used; i++){
      Category cat = cats[i].cat;
      load_method_ t load_method = (load_method_t)cats[i].method;//取出分类的 load 方法直接调用
    ....
    }
    //先调用父类的 load 方法,后调用子类的 load 方法.这里是一个递归调用,保证父类先调用,然后调用子类。
    static void schedule_class_load(Class cls) {
      if(!cls) return;
      assert(cls->isRealized());
      if(cls->data()->flags & RW_LOADED) return;
      schedule_calss_load(cls->superclass);// 保证先调用父类的
      add_class_to_loadable_list(cls); //将 cls 天剑到 loadable_classes数组的最后面
      cls->setInfo(RW_LOADED);
    }
    

    initialize

    • initialize 调用是通过消息机制调用的。所以分类有 initialize的话会调用分类的initialize
    • initialize会在类第一次收到消息的时候调用。
    • 调用顺序
      1.先调用父类的+initialize,再调用子类的+initialize,先初始化父类,再初始化子类,每个类只会初始化一次。
    • initialize是通过 objc_msgSend 调用的,如果子类没有实现 initialize方法就会调用父类的 initialize 方法,所以父类的 initialize 可能会被调用多次。如果分类实现了initialize 就会覆盖类本身的initialize 调用
    initialize 方法调用解析
    • 当我们调用一个方法时,会先去查找这个方法,在查找这个方法之前我们先去看这个类有没有初始化过,如果没有初始化过,我们就先调用 initialize 去初始化,在调用 initialize 初始化之前会先判断父类有没有初始化过,如果父类没有初始化过就先初始化父,然后再调用自己的 initialize,完成初始化过程,如果当前类已经初始化过,就不会再调用 initialize 去初始化了

    load 和 initialize 的区别

    • 调用方式:load 是根据函数地址直接调用,initialize 是通过消息机制(objc_msgSend)调用
    • 调用时间:loadruntime加载类分类的时候调用的(只会调用一次),initialize 是类第一次收到消息的时候调用,每一个类只会 initialize 一次(父类的 initialize 方法可能被调用多次)
    • 调用顺序 :load先调用类的 load,后调用分类的load,调用子类的 load 之前会先调用父类的 load;类的initialize 会被分类的 initialize 覆盖,先初始化父类,再初始化子类(如果子类没有 initialize,最终调用的是父类的initialize 方法)

    相关文章

      网友评论

          本文标题:load 和 initialize

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