objc中load、initialize方法的调用

1.load 的调用

结论


1.先调用类的 load 方法,先编译哪个类就先调用该类的 load.

2.在调用 load 之前调用父类 load 方法.

3.分类 load 方法不会覆盖本类的 load 方法.

1.准备工作

请添加图片描述


void registerObjCNotifiers(_dyld_objc_notify_mapped mapped, _dyld_objc_notify_init init, _dyld_objc_notify_unmapped unmapped)
{
	// record functions to call
	sNotifyObjCMapped	= mapped;
	sNotifyObjCInit		= init;
	sNotifyObjCUnmapped = unmapped;

	// call 'mapped' function with all images mapped so far
	try {
	    //  这里调用了  sNotifyObjCMapped 即 map_classes
		notifyBatchPartial(dyld_image_state_bound, true, NULL, false, true);
	}
	catch (const char* msg) {
		// ignore request to abort during registration
	}

	// <rdar://problem/32209809> call 'init' function on all images already init'ed (below libSystem)
	for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
		ImageLoader* image = *it;
		if ( (image->getState() == dyld_image_state_initialized) && image->notifyObjC() ) {
			dyld3::ScopedTimer timer(DBG_DYLD_TIMING_OBJC_INIT, (uint64_t)image->machHeader(), 0, 0);
			(*sNotifyObjCInit)(image->getRealPath(), image->machHeader());
		}
	}
}


2.什么时候调用 sNotifyObjCMapped?

registerObjCNotifiers-> notifyBatch -> notifyBatchPartial-> map_images

堆栈完全印证


(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 8.1
  * frame #0: 0x000000010049ce23 libobjc.A.dylib`map_images(count=56, paths=0x00007ff7bfefc570, mhdrs=0x00007ff7bfefca40) at objc-runtime-new.mm:3159:24
    frame #1: 0x00007ff8001fc740 dyld`invocation function for block in dyld4::RuntimeState::setObjCNotifiers(void (*)(unsigned int, char const* const*, mach_header const* const*), void (*)(char const*, mach_header const*), void (*)(char const*, mach_header const*), void (*)(mach_header const*, void*, mach_header const*, void const*), void (*)(unsigned int, _dyld_objc_notify_mapped_info const*))::$_8::operator()() const + 637
    frame #2: 0x00007ff8001f46d9 dyld`dyld4::RuntimeState::withLoadersReadLock(void () block_pointer) + 41
    frame #3: 0x00007ff8001f95db dyld`dyld4::RuntimeState::setObjCNotifiers(void (*)(unsigned int, char const* const*, mach_header const* const*), void (*)(char const*, mach_header const*), void (*)(char const*, mach_header const*), void (*)(mach_header const*, void*, mach_header const*, void const*), void (*)(unsigned int, _dyld_objc_notify_mapped_info const*)) + 209
    frame #4: 0x00007ff80021f188 dyld`dyld4::APIs::_dyld_objc_register_callbacks(_dyld_objc_callbacks const*) + 138
    frame #5: 0x00000001004eecfd libobjc.A.dylib`_objc_init at objc-os.mm:815:5
    frame #6: 0x00000001000adfb9 libdispatch.dylib`_os_object_init + 13
    frame #7: 0x00000001000bfd9c libdispatch.dylib`libdispatch_init + 363
    frame #8: 0x00007ff80c3b1898 libSystem.B.dylib`libSystem_initializer + 238
    frame #9: 0x00007ff8002063fb dyld`invocation function for block in dyld4::Loader::findAndRunAllInitializers(dyld4::RuntimeState&) const::$_0::operator()() const + 175
    frame #10: 0x00007ff800244b7a dyld`invocation function for block in dyld3::MachOAnalyzer::forEachInitializer(Diagnostics&, dyld3::MachOAnalyzer::VMAddrConverter const&, void (unsigned int) block_pointer, void const*) const + 242
    frame #11: 0x00007ff800238f22 dyld`invocation function for block in dyld3::MachOFile::forEachSection(void (dyld3::MachOFile::SectionInfo const&, bool, bool&) block_pointer) const + 577
    frame #12: 0x00007ff8001e90af dyld`dyld3::MachOFile::forEachLoadCommand(Diagnostics&, void (load_command const*, bool&) block_pointer) const + 245
    frame #13: 0x00007ff8002380bf dyld`dyld3::MachOFile::forEachSection(void (dyld3::MachOFile::SectionInfo const&, bool, bool&) block_pointer) const + 175
    frame #14: 0x00007ff80024473a dyld`dyld3::MachOAnalyzer::forEachInitializer(Diagnostics&, dyld3::MachOAnalyzer::VMAddrConverter const&, void (unsigned int) block_pointer, void const*) const + 470
    frame #15: 0x00007ff80020366c dyld`dyld4::Loader::findAndRunAllInitializers(dyld4::RuntimeState&) const + 220
    frame #16: 0x00007ff800224bdd dyld`dyld4::APIs::runAllInitializersForMain() + 65
    frame #17: 0x00007ff8001ee874 dyld`dyld4::prepare(dyld4::APIs&, dyld3::MachOAnalyzer const*) + 3761
    frame #18: 0x00007ff8001ed3bd dyld`start + 1805

3.什么时候调用 load 方法

_dyld_start -> dyldbootstrap::start -> dyld::_main -> initializeMainExecutable -> ImageLoader::runInitializers -> ImageLoader::processInitializers -> ImageLoader::recursiveInitialization -> notifySingle -> sNotifyObjCInit -> load_images -> +load


(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 9.1
  * frame #0: 0x00000001000033d0 KCObjcBuild`+[LGSon load](self=LGSon, _cmd="load") at main.m:57:5 [opt]
    frame #1: 0x0000000100497026 libobjc.A.dylib`call_class_loads() at objc-loadmethod.mm:204:9
    frame #2: 0x0000000100496f0d libobjc.A.dylib`call_load_methods at objc-loadmethod.mm:353:13
    frame #3: 0x000000010049cf6d libobjc.A.dylib`load_images(path="/Users/lee/Library/Developer/Xcode/DerivedData/objc-ascfiajdmnkqzabgrazgkmriraio/Build/Products/Debug/KCObjcBuild", mh=0x0000000100000000) at objc-runtime-new.mm:3295:5
    frame #4: 0x00007ff8001f96d8 dyld`dyld4::RuntimeState::notifyObjCInit(dyld4::Loader const*) + 170
    frame #5: 0x00007ff80020384f dyld`dyld4::Loader::runInitializersBottomUp(dyld4::RuntimeState&, dyld3::Array<dyld4::Loader const*>&) const + 167
    frame #6: 0x00007ff80020646f dyld`dyld4::Loader::runInitializersBottomUpPlusUpwardLinks(dyld4::RuntimeState&) const::$_1::operator()() const + 97
    frame #7: 0x00007ff8002038f1 dyld`dyld4::Loader::runInitializersBottomUpPlusUpwardLinks(dyld4::RuntimeState&) const + 93
    frame #8: 0x00007ff800224cd2 dyld`dyld4::APIs::runAllInitializersForMain() + 310
    frame #9: 0x00007ff8001ee874 dyld`dyld4::prepare(dyld4::APIs&, dyld3::MachOAnalyzer const*) + 3761
    frame #10: 0x00007ff8001ed3bd dyld`start + 1805

堆栈印证

4.如何获取到类和对应的load 方法?

按照有序,将 需要被执行 load 的class 添加到 loadable_classes 中


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->getSuperclass());

    add_class_to_loadable_list(cls);
    cls->setInfo(RW_LOADED);
}



可以看到递归调用 schedule_class_load ,优先添加 父类,再添加子类


void add_class_to_loadable_list(Class cls)
{
    IMP method;

    lockdebug::assert_locked(&loadMethodLock);

    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++;
}




调用堆栈


(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 10.1
  * frame #0: 0x0000000100496bfa libobjc.A.dylib`add_class_to_loadable_list(cls=0x00007ff843c3b278) at objc-loadmethod.mm:86:26
    frame #1: 0x000000010049f4a0 libobjc.A.dylib`schedule_class_load(cls=0x00007ff843c3b278) at objc-runtime-new.mm:3954:5
    frame #2: 0x000000010049d168 libobjc.A.dylib`prepare_load_methods(mhdr=0x00007ff80144e000) at objc-runtime-new.mm:3976:9
    frame #3: 0x000000010049cf5a libobjc.A.dylib`load_images(path="/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation", mh=0x00007ff80144e000) at objc-runtime-new.mm:3291:9
    frame #4: 0x00007ff8001f96d8 dyld`dyld4::RuntimeState::notifyObjCInit(dyld4::Loader const*) + 170
    frame #5: 0x00007ff80020384f dyld`dyld4::Loader::runInitializersBottomUp(dyld4::RuntimeState&, dyld3::Array<dyld4::Loader const*>&) const + 167
    frame #6: 0x00007ff80020383d dyld`dyld4::Loader::runInitializersBottomUp(dyld4::RuntimeState&, dyld3::Array<dyld4::Loader const*>&) const + 149
    frame #7: 0x00007ff80020646f dyld`dyld4::Loader::runInitializersBottomUpPlusUpwardLinks(dyld4::RuntimeState&) const::$_1::operator()() const + 97
    frame #8: 0x00007ff8002038f1 dyld`dyld4::Loader::runInitializersBottomUpPlusUpwardLinks(dyld4::RuntimeState&) const + 93
    frame #9: 0x00007ff800224cd2 dyld`dyld4::APIs::runAllInitializersForMain() + 310
    frame #10: 0x00007ff8001ee874 dyld`dyld4::prepare(dyld4::APIs&, dyld3::MachOAnalyzer const*) + 3761
    frame #11: 0x00007ff8001ed3bd dyld`start + 1805


再在 prepare_load_methods 方法中添加分类可加载的 class


void prepare_load_methods(const headerType *mhdr)
{
    size_t count, i;

    lockdebug::assert_locked(&runtimeLock);

    classref_t const *classlist =
        _getObjc2NonlazyClassList(mhdr, &count);
    for (i = 0; i < count; i++) {
        schedule_class_load(remapClass(classlist[i]));
    }

    category_t * const *categorylist = _getObjc2NonlazyCategoryList(mhdr, &count);
    for (i = 0; i < count; i++) {
        category_t *cat = categorylist[i];
        Class cls = remapClass(cat->cls);
        if (!cls) continue;  // category for ignored weak-linked class
        if (cls->isSwiftStable()) {
            _objc_fatal("Swift class extensions and categories on Swift "
                        "classes are not allowed to have +load methods");
        }
        realizeClassWithoutSwift(cls, nil);
        ASSERT(cls->ISA()->isRealized());
        add_category_to_loadable_list(cat);
    }
}

5.load 方法的执行

在 call_class_loads 方法中,按序遍历 loadable_classes 数组


static void call_class_loads(void)
{
    int i;
    
    // Detach current loadable list.
    struct loadable_class *classes = loadable_classes;
    int used = loadable_classes_used;
    loadable_classes = nil;
    loadable_classes_allocated = 0;
    loadable_classes_used = 0;
    
    // Call all +loads for the detached list.
    for (i = 0; i < used; i++) {
        Class cls = classes[i].cls;
        load_method_t load_method = (load_method_t)classes[i].method;
        if (!cls) continue; 

        if (PrintLoading) {
            _objc_inform("LOAD: +[%s load]\n", cls->nameForLogging());
        }
        (*load_method)(cls, @selector(load));
    }
    
    // Destroy the detached list.
    if (classes) free(classes);
}

所以有网上常说的


1.先调用类的 load 方法,先编译哪个类就先调用该类的 load.

2.在调用 load 之前调用父类 load 方法.

3.分类 load 方法不会覆盖本类的 load 方法.

2.load 的调用

结论


1.initialize 方法先初始化父类,之后再初始化子类.

2.如果子类未实现 initialize 方法,就会调用父类的 initialize 方法.

3.如果分类实现了 initialize 方法,会覆盖本类 initialize 方法.

1.为 NSObject 根类添加 initialize 方法

// 如果根类尚未实现,则会获得额外的方法实现。这些方法在类别替换之前生效。
    if (cls->isRootMetaclass()) {
        // root metaclass
        addMethod(cls, @selector(initialize), (IMP)&objc_noop_imp, "", NO);
    }

调用堆栈


(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 11.1
  * frame #0: 0x00000001004b99b5 libobjc.A.dylib`methodizeClass(cls=0x00000001005180f0, previously=0x0000000000000000) at objc-runtime-new.mm:1547:19
    frame #1: 0x000000010049c00e libobjc.A.dylib`realizeClassWithoutSwift(cls=0x00000001005180f0, previously=0x0000000000000000) at objc-runtime-new.mm:2747:5
    frame #2: 0x000000010049bde5 libobjc.A.dylib`realizeClassWithoutSwift(cls=0x0000000100518140, previously=0x0000000000000000) at objc-runtime-new.mm:2665:15
    frame #3: 0x000000010049bdc2 libobjc.A.dylib`realizeClassWithoutSwift(cls=0x000000010011d700, previously=0x0000000000000000) at objc-runtime-new.mm:2664:16
    frame #4: 0x000000010049bdc2 libobjc.A.dylib`realizeClassWithoutSwift(cls=0x00007ff843c221f0, previously=0x0000000000000000) at objc-runtime-new.mm:2664:16
    frame #5: 0x000000010049bdc2 libobjc.A.dylib`realizeClassWithoutSwift(cls=0x00007ff843c22740, previously=0x0000000000000000) at objc-runtime-new.mm:2664:16    frame #6: 0x000000010049e21a libobjc.A.dylib`_read_images(hList=0x00007ff7bfefb3d0, hCount=56, totalClasses=2149, unoptimizedTotalClasses=2149) at objc-runtime-new.mm:3852:13
    frame #7: 0x00000001004edb38 libobjc.A.dylib`map_images_nolock(mhCount=56, mhPaths=0x00007ff7bfefc570, mhdrs=0x00007ff7bfefca40, disabledClassROEnforcement=0x00007ff7bfefb6e7) at objc-os.mm:470:9
    frame #8: 0x000000010049ce61 libobjc.A.dylib`map_images(count=56, paths=0x00007ff7bfefc570, mhdrs=0x00007ff7bfefca40) at objc-runtime-new.mm:3165:9
    frame #9: 0x00007ff8001fc740 dyld`invocation function for block in dyld4::RuntimeState::setObjCNotifiers(void (*)(unsigned int, char const* const*, mach_header const* const*), void (*)(char const*, mach_header const*), void (*)(char const*, mach_header const*), void (*)(mach_header const*, void*, mach_header const*, void const*), void (*)(unsigned int, _dyld_objc_notify_mapped_info const*))::$_8::operator()() const + 637
    frame #10: 0x00007ff8001f46d9 dyld`dyld4::RuntimeState::withLoadersReadLock(void () block_pointer) + 41
    frame #11: 0x00007ff8001f95db dyld`dyld4::RuntimeState::setObjCNotifiers(void (*)(unsigned int, char const* const*, mach_header const* const*), void (*)(char const*, mach_header const*), void (*)(char const*, mach_header const*), void (*)(mach_header const*, void*, mach_header const*, void const*), void (*)(unsigned int, _dyld_objc_notify_mapped_info const*)) + 209
    frame #12: 0x00007ff80021f188 dyld`dyld4::APIs::_dyld_objc_register_callbacks(_dyld_objc_callbacks const*) + 138
    frame #13: 0x00000001004eecfd libobjc.A.dylib`_objc_init at objc-os.mm:815:5
    frame #14: 0x00000001000adfb9 libdispatch.dylib`_os_object_init + 13
    frame #15: 0x00000001000bfd9c libdispatch.dylib`libdispatch_init + 363
    frame #16: 0x00007ff80c3b1898 libSystem.B.dylib`libSystem_initializer + 238
    frame #17: 0x00007ff8002063fb dyld`invocation function for block in dyld4::Loader::findAndRunAllInitializers(dyld4::RuntimeState&) const::$_0::operator()() const + 175
    frame #18: 0x00007ff800244b7a dyld`invocation function for block in dyld3::MachOAnalyzer::forEachInitializer(Diagnostics&, dyld3::MachOAnalyzer::VMAddrConverter const&, void (unsigned int) block_pointer, void const*) const + 242
    frame #19: 0x00007ff800238f22 dyld`invocation function for block in dyld3::MachOFile::forEachSection(void (dyld3::MachOFile::SectionInfo const&, bool, bool&) block_pointer) const + 577
    frame #20: 0x00007ff8001e90af dyld`dyld3::MachOFile::forEachLoadCommand(Diagnostics&, void (load_command const*, bool&) block_pointer) const + 245
    frame #21: 0x00007ff8002380bf dyld`dyld3::MachOFile::forEachSection(void (dyld3::MachOFile::SectionInfo const&, bool, bool&) block_pointer) const + 175
    frame #22: 0x00007ff80024473a dyld`dyld3::MachOAnalyzer::forEachInitializer(Diagnostics&, dyld3::MachOAnalyzer::VMAddrConverter const&, void (unsigned int) block_pointer, void const*) const + 470
    frame #23: 0x00007ff80020366c dyld`dyld4::Loader::findAndRunAllInitializers(dyld4::RuntimeState&) const + 220
    frame #24: 0x00007ff800224bdd dyld`dyld4::APIs::runAllInitializersForMain() + 65
    frame #25: 0x00007ff8001ee874 dyld`dyld4::prepare(dyld4::APIs&, dyld3::MachOAnalyzer const*) + 3761
    frame #26: 0x00007ff8001ed3bd dyld`start + 1805

2.先调用父类 initialize 方法


void initializeNonMetaClass(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->getSuperclass();
    if (supercls  &&  !supercls->isInitialized()) {
        initializeNonMetaClass(supercls);
    }
     ...
     }

调用堆栈


(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 12.1
    frame #0: 0x00000001000030f0 KCObjcBuild`+[LGPerson initialize](self=LGPerson, _cmd="initialize") at main.m:43:5 [opt]
    frame #1: 0x000000010049236c libobjc.A.dylib`_CALLING_SOME_+initialize_METHOD(cls=LGPerson) at objc-initialize.mm:384:5
    frame #2: 0x00000001004928b1 libobjc.A.dylib`initializeNonMetaClass(cls=LGPerson) at objc-initialize.mm:549:13
    frame #3: 0x00000001004926c3 libobjc.A.dylib`initializeNonMetaClass(cls=LGSon) at objc-initialize.mm:505:9
    frame #4: 0x000000010049b51e libobjc.A.dylib`initializeAndMaybeRelock(cls=0x0000000100008720, inst=0x0000000100008748, lock=0x000000010051b0c0, leaveLocked=true) at objc-runtime-new.mm:2220:5
    frame #5: 0x00000001004cb25a libobjc.A.dylib`initializeAndLeaveLocked(cls=0x0000000100008720, obj=0x0000000100008748, lock=0x000000010051b0c0) at objc-runtime-new.mm:2236:12
    frame #6: 0x00000001004ac2d0 libobjc.A.dylib`realizeAndInitializeIfNeeded_locked(inst=0x0000000100008748, cls=0x0000000100008720, initialize=true) at objc-runtime-new.mm:6769:15
    frame #7: 0x00000001004abd5d libobjc.A.dylib`lookUpImpOrForward(inst=0x0000000100008748, sel="alloc", cls=0x0000000100008720, behavior=11) at objc-runtime-new.mm:6886:11
    frame #8: 0x00000001004e77db libobjc.A.dylib`_objc_msgSend_uncached at objc-msg-x86_64.s:1153
    frame #9: 0x00000001004fc554 libobjc.A.dylib`objc_alloc_init [inlined] callAlloc(cls=LGSon, checkNil=true, allocWithZone=false) at NSObject.mm:2011:12
    frame #10: 0x00000001004fc4ac libobjc.A.dylib`objc_alloc_init(cls=LGSon) at NSObject.mm:2041:13
    frame #11: 0x0000000100003a8d KCObjcBuild`main(argc=1, argv=0x00007ff7bfeff450) at main.m:207:24 [opt]
    frame #12: 0x00007ff8001ed41f dyld`start + 1903




3.再调用子类 initialize 方法

void callInitialize(Class cls)
{
    ((void(*)(Class, SEL))objc_msgSend)(cls, @selector(initialize));
    asm("");
}

void initializeNonMetaClass(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->getSuperclass();
    if (supercls  &&  !supercls->isInitialized()) {
        initializeNonMetaClass(supercls);
    }
    
    // Try to atomically set CLS_INITIALIZING.
    SmallVector<_objc_willInitializeClassCallback, 1> localWillInitializeFuncs;
    {
        monitor_locker_t lock(classInitLock);
        if (!cls->isInitialized() && !cls->isInitializing()) {
            cls->setInitializing();
            reallyInitialize = YES;

            // Grab a copy of the will-initialize funcs with the lock held.
            localWillInitializeFuncs.initFrom(willInitializeFuncs);
        }
    }
    
    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);

        if (MultithreadedForkChild) {
            // LOL JK we don't really call +initialize methods after fork().
            performForkChildInitialize(cls, supercls);
            return;
        }
        
        for (auto callback : localWillInitializeFuncs)
            callback.f(callback.context, 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: thread %p: calling +[%s initialize]",
                         objc_thread_self(), cls->nameForLogging());
        }

        // Exceptions: A +initialize call that throws an exception 
        // is deemed to be a complete and successful +initialize.
        //
        @try
        {
            callInitialize(cls);
            }
            ...
}

调用堆栈


(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 8.1
    frame #0: 0x00000001000033c0 KCObjcBuild`+[LGSon initialize](self=LGSon, _cmd="initialize") at main.m:61:5 [opt]
    frame #1: 0x000000010049236c libobjc.A.dylib`_CALLING_SOME_+initialize_METHOD(cls=LGSon) at objc-initialize.mm:384:5
    frame #2: 0x00000001004928b1 libobjc.A.dylib`initializeNonMetaClass(cls=LGSon) at objc-initialize.mm:549:13
    frame #3: 0x000000010049b51e libobjc.A.dylib`initializeAndMaybeRelock(cls=0x0000000100008708, inst=0x0000000100008730, lock=0x000000010051b0c0, leaveLocked=true) at objc-runtime-new.mm:2220:5
    frame #4: 0x00000001004cb25a libobjc.A.dylib`initializeAndLeaveLocked(cls=0x0000000100008708, obj=0x0000000100008730, lock=0x000000010051b0c0) at objc-runtime-new.mm:2236:12
    frame #5: 0x00000001004ac2d0 libobjc.A.dylib`realizeAndInitializeIfNeeded_locked(inst=0x0000000100008730, cls=0x0000000100008708, initialize=true) at objc-runtime-new.mm:6769:15
    frame #6: 0x00000001004abd5d libobjc.A.dylib`lookUpImpOrForward(inst=0x0000000100008730, sel="alloc", cls=0x0000000100008708, behavior=11) at objc-runtime-new.mm:6886:11
    frame #7: 0x00000001004e77db libobjc.A.dylib`_objc_msgSend_uncached at objc-msg-x86_64.s:1153
    frame #8: 0x00000001004fc554 libobjc.A.dylib`objc_alloc_init [inlined] callAlloc(cls=LGSon, checkNil=true, allocWithZone=false) at NSObject.mm:2011:12
    frame #9: 0x00000001004fc4ac libobjc.A.dylib`objc_alloc_init(cls=LGSon) at NSObject.mm:2041:13
    frame #10: 0x0000000100003a8d KCObjcBuild`main(argc=1, argv=0x00007ff7bfeff450) at main.m:202:24 [opt]
    frame #11: 0x00007ff8001ed41f dyld`start + 1903

4.分类 initialize 方法会覆盖当前类initialize 方法

调用堆栈和 3.再调用子类 initialize 方法 完全一致,说明当前类的 initialize 方法被分类代替

initialize也只是一个普通的方法,符合下面调用特征

1.当分类、原来类、原来类的父类中有相同方法时,方法调用的优先级:分类(最后参与编译的分类优先) –> 原来类 –> 父类,即先去调用分类中的方法,分类中没这个方法再去原来类中找,原来类中没有再去父类中找。

2.分类可以重新实现原来类中的方法,但是会覆盖掉原来的方法,会导致原来的方法没法再使用(实际上并没有真的替换,而是Category的方法被放到了新方法列表的前面,而原来类的方法被放到了新方法列表的后面,这也就是我们平常所说的Category的方法会“覆盖”掉原来类的同名方法,这是因为运行时在查找方法的时候是顺着方法列表的顺序查找的,它只要一找到对应名字的方法,就会罢休,殊不知后面可能还有一样名字的方法)。

void callInitialize(Class cls)
{
    ((void(*)(Class, SEL))objc_msgSend)(cls, @selector(initialize));
    asm("");
}

void initializeNonMetaClass(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->getSuperclass();
    if (supercls  &&  !supercls->isInitialized()) {
        initializeNonMetaClass(supercls);
    }
    
    // Try to atomically set CLS_INITIALIZING.
    SmallVector<_objc_willInitializeClassCallback, 1> localWillInitializeFuncs;
    {
        monitor_locker_t lock(classInitLock);
        if (!cls->isInitialized() && !cls->isInitializing()) {
            cls->setInitializing();
            reallyInitialize = YES;

            // Grab a copy of the will-initialize funcs with the lock held.
            localWillInitializeFuncs.initFrom(willInitializeFuncs);
        }
    }
    
    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);

        if (MultithreadedForkChild) {
            // LOL JK we don't really call +initialize methods after fork().
            performForkChildInitialize(cls, supercls);
            return;
        }
        
        for (auto callback : localWillInitializeFuncs)
            callback.f(callback.context, 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: thread %p: calling +[%s initialize]",
                         objc_thread_self(), cls->nameForLogging());
        }

        // Exceptions: A +initialize call that throws an exception 
        // is deemed to be a complete and successful +initialize.
        //
        @try
        {
            callInitialize(cls);
            }
            ...
}

调用堆栈

(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 12.1
  * frame #0: 0x00000001000036c0 KCObjcBuild`+[LGSon(self=LGSon, _cmd="initialize") initialize] at main.m:127:5 [opt]
    frame #1: 0x000000010049236c libobjc.A.dylib`_CALLING_SOME_+initialize_METHOD(cls=LGSon) at objc-initialize.mm:384:5
    frame #2: 0x00000001004928b1 libobjc.A.dylib`initializeNonMetaClass(cls=LGSon) at objc-initialize.mm:549:13
    frame #3: 0x000000010049b51e libobjc.A.dylib`initializeAndMaybeRelock(cls=0x0000000100008798, inst=0x00000001000087c0, lock=0x000000010051b0c0, leaveLocked=true) at objc-runtime-new.mm:2220:5
    frame #4: 0x00000001004cb25a libobjc.A.dylib`initializeAndLeaveLocked(cls=0x0000000100008798, obj=0x00000001000087c0, lock=0x000000010051b0c0) at objc-runtime-new.mm:2236:12
    frame #5: 0x00000001004ac2d0 libobjc.A.dylib`realizeAndInitializeIfNeeded_locked(inst=0x00000001000087c0, cls=0x0000000100008798, initialize=true) at objc-runtime-new.mm:6769:15
    frame #6: 0x00000001004abd5d libobjc.A.dylib`lookUpImpOrForward(inst=0x00000001000087c0, sel="alloc", cls=0x0000000100008798, behavior=11) at objc-runtime-new.mm:6886:11
    frame #7: 0x00000001004e77db libobjc.A.dylib`_objc_msgSend_uncached at objc-msg-x86_64.s:1153
    frame #8: 0x00000001004fc554 libobjc.A.dylib`objc_alloc_init [inlined] callAlloc(cls=LGSon, checkNil=true, allocWithZone=false) at NSObject.mm:2011:12
    frame #9: 0x00000001004fc4ac libobjc.A.dylib`objc_alloc_init(cls=LGSon) at NSObject.mm:2041:13
    frame #10: 0x0000000100003a8d KCObjcBuild`main(argc=1, argv=0x00007ff7bfeff450) at main.m:223:24 [opt]
    frame #11: 0x00007ff8001ed41f dyld`start + 1903

所以有网上常说的


1.initialize 方法先初始化父类,之后再初始化子类.

2.如果子类未实现 initialize 方法,就会调用父类的 initialize 方法.

3.如果分类实现了 initialize 方法,会覆盖本类 initialize 方法.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值