+load +initialize

+load方法

在app启动的时候各个类的+load方法都会被调用+load方法不是通过消息机制调用的,它是直接调用的,因此无论是在子类或者category中复写此方法,复写的+load方法都会被调用,查看runtime的代码可知调用的顺序为

父类->子类->分类。(原因是runtime会把所有类的+load方法放到一个列表中,然后按顺序调用,所有category的+load方法放到一个列表中,然后也按顺序调用,所以当所有类的+load方法都执行完成后才开始去执行分类的+load方法)。所有类的+load方法在调用列表中的顺序由两个因素决定,一个是此类文件的编译顺序,一个是递归调用的顺序,即从父类到子类。所有分类的+load方法在调用列表中的顺序只由编译顺序决定

 

schedule_class_load

call_class_load

 

runtime代码如下:

static void schedule_class_load(Class cls)

{

    if (!cls) return;

    assert(cls->isRealized());  // _read_images should realize

    if (cls->data()->flags & RW_LOADED) return;

    // Ensure superclass-first ordering

    schedule_class_load(cls->superclass);

    add_class_to_loadable_list(cls);

    cls->setInfo(RW_LOADED); 

}

 

 

prepare_load_methods

call_load_methods

 

void call_load_methods(void)

{

    static bool loading = NO;

    bool more_categories;

 

    loadMethodLock.assertLocked();

 

    // Re-entrant calls do nothing; the outermost call will finish the job.

    if (loading) return;

    loading = YES;

 

    void *pool = objc_autoreleasePoolPush();

 

    do {

        // 1. Repeatedly call class +loads until there aren't any more

        while (loadable_classes_used > 0) {

            call_class_loads();

        }

 

        // 2. Call category +loads ONCE

        more_categories = call_category_loads();

 

        // 3. Run more +loads if there are classes OR more untried categories

    } while (loadable_classes_used > 0  ||  more_categories);

 

    objc_autoreleasePoolPop(pool);

 

    loading = NO;

}

 

 

+initialize

与+load方法不同+initialize方法是通过消息的方式发送的(msgSend),所以+initialize方法可以被子类或者分类覆盖每个类第一次被用到的时候,runtime都会调用 _class_initialize(Class cls)方法,_class_initialize(Class cls)也是一个递归调用的方法,当发现cls的父类没有调用此方法时,会递归调用_class_initialize(cls->supercls),调用时会向该类发送initialize消息,此方法被调用完成后cls->isInitialized()这个属性会变成true

注意这里存在一个类的initialize方法被调用多次的可能当子类没有实现initialize方法时,父类的initialize方法可能被调用多次

举个例子:

有两个类:Person,Girl,Girl继承Person

如果只有Person实现了initialize方法,那么当这Girl类被用到时,Person的这个initialize方法会被调用两次,一次是父类调用_class_initializePerson时发送的,另一次是调用_class_initializeGirl)时发送的,因为给Girl发送initialize的时候发现Girl并没有实现此方法,所以此方法被转发到了Girl的父类,即Person的类对象。

可以这么理解,每个类对应的_class_initialize(Class cls)这个方法只会被调用一次,调用的顺序为从父类到子类,在_class_initialize(Class cls)这个方法中会向当前的类对象发送initialize方法。如果当前类没有实现initialize方法则依次去父类找

_class_initialize(Class cls)

void _class_initialize(Class cls)

{

    assert(!cls->isMetaClass());

    Class supercls;

    BOOL reallyInitialize = NO;

    // Make sure super is done initializing BEFORE beginning to initialize cls.

    // See note about deadlock above.

    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;

        }

    }

    

    if (reallyInitialize) {

        // We successfully set the CLS_INITIALIZING bit. Initialize the class.

        

        // Record that we're initializing this class so we can message it.

        _setThisThreadIsInitializingClass(cls);

        

        // Send the +initialize message.

        // Note that +initialize is sent to the superclass (again) if 

        // this class doesn't implement +initialize. 2157218

        if (PrintInitializing) {

            _objc_inform("INITIALIZE: calling +[%s initialize]",

                         cls->nameForLogging());

        }

        ((void(*)(Class, SEL))objc_msgSend)(cls, SEL_initialize);

        if (PrintInitializing) {

            _objc_inform("INITIALIZE: finished +[%s initialize]",

                         cls->nameForLogging());

        }        

        

        // Done initializing. 

        // If the superclass is also done initializing, then update 

        //   the info bits and notify waiting threads.

        // If not, update them later. (This can happen if this +initialize 

        //   was itself triggered from inside a superclass +initialize.)

        monitor_locker_t lock(classInitLock);

        if (!supercls  ||  supercls->isInitialized()) {

            _finishInitializing(cls, supercls);

        } else {

            _finishInitializingAfter(cls, supercls);

        }

        return;

    }

    

    else if (cls->isInitializing()) {

        // We couldn't set INITIALIZING because INITIALIZING was already set.

        // If this thread set it earlier, continue normally.

        // If some other thread set it, block until initialize is done.

        // It's ok if INITIALIZING changes to INITIALIZED while we're here, 

        //   because we safely check for INITIALIZED inside the lock 

        //   before blocking.

        if (_thisThreadIsInitializingClass(cls)) {

            return;

        } else {

            monitor_locker_t lock(classInitLock);

            while (!cls->isInitialized()) {

                classInitLock.wait();

            }

            return;

        }

    }

    

    else if (cls->isInitialized()) {

        // Set CLS_INITIALIZING failed because someone else already 

        //   initialized the class. Continue normally.

        // NOTE this check must come AFTER the ISINITIALIZING case.

        // Otherwise: Another thread is initializing this class. ISINITIALIZED 

        //   is false. Skip this clause. Then the other thread finishes 

        //   initialization and sets INITIALIZING=no and INITIALIZED=yes. 

        //   Skip the ISINITIALIZING clause. Die horribly.

        return;

    }

    

    else {

        // We shouldn't be here. 

        _objc_fatal("thread-safe class init in objc runtime is buggy!");

    }

}

猜你喜欢

转载自www.cnblogs.com/yibinpan/p/9693184.html