OC中的Category(三)

OC中的Category(三)

OC中+initialize函数加载和调用

OC对象是在查找方法时判断自己有没有初始化,如果没有就会调用初始化方法,在调用自己的初始化方法之前会调用父类的初始化方法。

调用initialize方法是通过runtime的objc_msgSend的方式调用,所以会存在如果子类没有实现会调用父类的initialize方法,并且优先调用类分类中存在的initializ方法

  • +initialize方法会在类第一次接收到消息时调用
  • 调用顺序:
    先调用父类的+initialize,再调用子类的+initialize
    (先初始化父类,再初始化子类,每个类只会初始化1次)

+initialize和+load的区别

  1. 调用方式
  • load是根据函数地址直接调用
  • initialize是通过objc_msgSend调用,如果子类没有实现+initialize,会调用父类的+initialize(所以父类的+initialize可能会被调用多次)如果分类实现了+initialize,就覆盖类本身的+initialize调用
  1. 调用时刻
  • load是runtime加载类、分类的时候调用(只会调用1次)
  • initialize是类第一次接收到消息的时候调用,每一个类只会initialize一次(父类的initialize方法可能会被调用多次)

load、initialize的调用顺序?

  1. load
  • 先调用类的load,先编译的类,优先调用load,调用子类的load之前,会先调用父类的load

  • 再调用分类的load,
    先编译的分类,优先调用load

  1. initialize
  • 先初始化父类
  • 再初始化子类(可能最终调用的是父类的initialize方法)

源码分析

objc-run-timenew.mm文件,查找方法实现

runtime中initialize方法的调用
Method class_getInstanceMethod(Class cls, SEL sel)
{
    if (!cls  ||  !sel) return nil;

    // This deliberately avoids +initialize because it historically did so.

    // This implementation is a bit weird because it's the only place that 
    // wants a Method instead of an IMP.

#warning fixme build and search caches
        
    // Search method lists, try method resolver, etc.
    lookUpImpOrNil(cls, sel, nil, 
                   NO/*initialize*/, NO/*cache*/, YES/*resolver*/);

#warning fixme build and search caches

    return _class_getMethod(cls, sel);
}

IMP lookUpImpOrNil(Class cls, SEL sel, id inst, 
                   bool initialize, bool cache, bool resolver)
{
    IMP imp = lookUpImpOrForward(cls, sel, inst, initialize, cache, resolver);
    if (imp == _objc_msgForward_impcache) return nil;
    else return imp;
}

IMP lookUpImpOrForward(Class cls, SEL sel, id inst, 
                       bool initialize, bool cache, bool resolver)
{
    .
    .
    .
    if (initialize  &&  !cls->isInitialized()) {
        runtimeLock.unlockRead();
        _class_initialize (_class_getNonMetaClass(cls, inst));
        runtimeLock.read();
    }
    .
    .
    .
    
}
void _class_initialize(Class cls)
{
    assert(!cls->isMetaClass());
    Class supercls;
    bool reallyInitialize = NO;
    supercls = cls->superclass;
    if (supercls  &&  !supercls->isInitialized()) {
        _class_initialize(supercls);
    }
    
    callInitialize(cls);


}
void callInitialize(Class cls)
{
    ((void(*)(Class, SEL))objc_msgSend)(cls, SEL_initialize);
    asm("");
}


©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Category的本质<一>Category的本质<三>关联对象面试题1:Category中有load方法吗?lo...
    雪山飞狐_91ae阅读 5,171评论 15 38
  • 转至元数据结尾创建: 董潇伟,最新修改于: 十二月 23, 2016 转至元数据起始第一章:isa和Class一....
    40c0490e5268阅读 1,758评论 0 9
  • 一、基本使用 1、RevanPerson类 2、RevanPerson+RevanRun 3、RevanPerso...
    紫荆秋雪_文阅读 608评论 0 1
  • OC语言基础 1.类与对象 类方法 OC的类方法只有2种:静态方法和实例方法两种 在OC中,只要方法声明在@int...
    奇异果好补阅读 4,321评论 0 11
  • 一、Category 本质 我们知道,当调用一个对象的方法时,通过对象的 isa 指针找到类对象,然后在类对象的方...
    666真666阅读 719评论 0 4