iOS +load和+ initialize方法

+ load方法

1. +load方法会在runtime加载类、分类的时候调用
2. 每个类、分类的+load方法在程序运行中只调用一次
3. + load方法的调用顺序
  • 先调用类的+load
    • 按照编译先后,顺序调用
    • 调用子类的+load之前会先调用父类的+load,如果父类的+load已经调用过了则不需要再调用
  • 在调用分类的+load
    • 按照编译先后,顺序调用

+ initialize方法

官方API的解释:

运行库在类或从它继承的任何类从程序中发送第一个消息之前,向程序中的每个类发送初始化。超类在子类之前接收到这个消息。
runtime以线程安全的方式将初始化消息发送给类。也就是说,initialize由第一个线程运行向类发送消息,而试图向该类发送消息的任何其他线程将被阻塞,直到initialize完成。
如果子类没有实现initialize(运行时将调用从超类继承的实现),或者子类显式地调用[super initialize],那么超类实现可能会被调用多次。如果你想保护自己不被多次运行需要自己构造initialize方法的实现

+ (void)initialize {
 if (self == [ClassName self]) {
   // ... do the initialization ...
 }
}

因为initialize是以阻塞的方式调用的,所以将方法实现限制在尽可能少的必要工作量是很重要的。具体来说,任何获取其他类在其初始化方法中可能需要的锁的代码都可能导致死锁。因此,您不应该依赖于初始化来进行复杂的初始化,而应该将其限制为简单的类局部初始化。
其实官方讲的很详细了,但是如果要完全理解还是需要去看一下源码,了解initialize的机制

1. 在类第一次接收到消息(消息机制)时调用
2. 调用顺序
  • 先调用父类的+ initialize,再调用子类的+ initialize
  • 先初始化父类,再初始化子类,并且每个类只会初始化1次。如果子类没有重写+ initialize,那么会调用父类的+ initialize方法。
void callInitialize(Class cls)
{
    ((void(*)(Class, SEL))objc_msgSend)(cls, @selector(initialize));
    asm("");
}

/***********************************************************************
* class_initialize.  Send the '+initialize' message on demand to any
* uninitialized class. Force initialization of superclasses first.
**********************************************************************/
void initializeNonMetaClass(Class cls)
{
    ASSERT(!cls->isMetaClass());

    Class supercls;
    bool reallyInitialize = NO;
    // Try to atomically set CLS_INITIALIZING.
    SmallVector<_objc_willInitializeClassCallback, 1> localWillInitializeFuncs;
    {
        if (!cls->isInitialized() && !cls->isInitializing()) {
            cls->setInitializing();
            reallyInitialize = YES;
        }
    }
    // Make sure super is done initializing BEFORE beginning to initialize cls.
    // 在开始初始化cls之前,确保super已经完成初始化。
    supercls = cls->getSuperclass();
    // 检查父类是否有初始化
    if (supercls  &&  !supercls->isInitialized()) {
        // 初始化父类
        initializeNonMetaClass(supercls);
    }
    if (reallyInitialize) {
#if __OBJC2__
        @try
#endif
        {
            callInitialize(cls);
        }
        return;
    }
}

面试题

1. Category和Class Extension的区别?

  • Class Extension在编译的时候,它的数据就已经包含在类信息中
  • Category是在运行时,才将分类信息合并到主类中

2. load方法可以继承吗?

  • 可以,但是主动调用load方法实际是触发的obj_msgSend()消息发送机制(通过isa去找方法...)

3. +load+initialize方法的区别?他们在分类中的调用顺序?以及出现继承时他们的调用过程

区别

  • + load是runtime加载类、分类的时候调用的,且只会调用1次
  • + initialize是在第一次收到消息的时候,每一个类只会initialize一次,但是在父类中如果重写了该方法则可能执行多次。因为子类中如果没有重写initialize就会触发父类调用initialize方法。

调用顺序

  • + load
    先调用父类的load方法,再调用子类的load方法,最后调用分类的load方法,都是按照编译的先后顺序调用。
  • + initialize
    先初始化父类,再初始化子类。如果子类中没有重写initialize方法,那么会触发父类调用initialize方法。

你可能感兴趣的:(iOS +load和+ initialize方法)