美文网首页系统层知识OC 底层
iOS底层原理之类的加载处理

iOS底层原理之类的加载处理

作者: 尘舒 | 来源:发表于2020-01-10 00:43 被阅读0次

    1. _objc_init

    • 程序在启动时,先用dyld进行动态库的链接,做完一系列准备操作之后,会进入到_objc_init方法
    • 下面简单了解一下主角_dyld_objc_notify_register开始之前的各个初始化的目的,在此不做详细介绍了,因为我也介绍不清楚~
    void _objc_init(void)
    {
        static bool initialized = false;
        if (initialized) return;
        initialized = true;
        
        // fixme defer initialization until an objc-using image is found?
        environ_init();
        tls_init();
        static_init();
        lock_init();
        exception_init();
    
        _dyld_objc_notify_register(&map_images, load_images, unmap_image);
    }
    

    1.1 environ_init

    • 读取影响运行时的环境变量,可以使用 export OBJC_HELP=1 来打印环境变量帮助,下面展示一下打印的示例
    objc[3206]: Objective-C runtime debugging. Set variable=YES to enable.
    objc[3206]: OBJC_HELP: describe available environment variables
    objc[3206]: OBJC_PRINT_OPTIONS: list which options are set
    objc[3206]: OBJC_PRINT_IMAGES: log image and library names as they are loaded
    objc[3206]: OBJC_PRINT_IMAGE_TIMES: measure duration of image loading steps
    objc[3206]: OBJC_PRINT_LOAD_METHODS: log calls to class and category +load methods
    objc[3206]: OBJC_PRINT_INITIALIZE_METHODS: log calls to class +initialize methods
    objc[3206]: OBJC_PRINT_RESOLVED_METHODS: log methods created by +resolveClassMethod: and +resolveInstanceMethod:
    objc[3206]: OBJC_PRINT_CLASS_SETUP: log progress of class and category setup
    objc[3206]: OBJC_PRINT_PROTOCOL_SETUP: log progress of protocol setup
    objc[3206]: OBJC_PRINT_IVAR_SETUP: log processing of non-fragile ivars
    objc[3206]: OBJC_PRINT_VTABLE_SETUP: log processing of class vtables
    objc[3206]: OBJC_PRINT_VTABLE_IMAGES: print vtable images showing overridden methods
    objc[3206]: OBJC_PRINT_CACHE_SETUP: log processing of method caches
    
    

    1.2 tls_init

    • 关于线程key的绑定

    1.3 static_init

    • 运行C++静态构造函数,在dyld调用我们的静态构造函数之前,libc会调用_objc_init,所以需要我们自己做

    1.4 lock_init

    • 空实现

    1.5 exception_init

    • 初始化 libobjc的异常处理系统

    1.6 小结

    • 做完上述准备条件之后,开始进入主角_dyld_objc_notify_register,通过注释可以知道该方法仅仅只用来在objc的运行时使用 ,进行map_imagesload_images
    //
    // Note: only for use by objc runtime
    // Register handlers to be called when objc images are mapped, unmapped, and initialized.
    // Dyld will call back the "mapped" function with an array of images that contain an objc-image-info section.
    // Those images that are dylibs will have the ref-counts automatically bumped, so objc will no longer need to
    // call dlopen() on them to keep them from being unloaded.  During the call to _dyld_objc_notify_register(),
    // dyld will call the "mapped" function with already loaded objc images.  During any later dlopen() call,
    // dyld will also call the "mapped" function.  Dyld will call the "init" function when dyld would be called
    // initializers in that image.  This is when objc calls any +load methods in that image.
    //
    void _dyld_objc_notify_register(_dyld_objc_notify_mapped    mapped,
                                    _dyld_objc_notify_init      init,
                                    _dyld_objc_notify_unmapped  unmapped);
    

    2. map_images

    /***********************************************************************
    * map_images
    * Process the given images which are being mapped in by dyld.
    * Calls ABI-agnostic code after taking ABI-specific locks.
    *
    * Locking: write-locks runtimeLock
    **********************************************************************/
    void
    map_images(unsigned count, const char * const paths[],
               const struct mach_header * const mhdrs[])
    {
        mutex_locker_t lock(runtimeLock);
        return map_images_nolock(count, paths, mhdrs);
    }
    
    • map_images_nolock方法内部,找到关键代码,针对hCount做完一系列判断条件之后,开始_read_images读取镜像文件到内存,把类、分类、属性、方法、协议等全部读取到内存中去
        if (hCount > 0) {
            _read_images(hList, hCount, totalClasses, unoptimizedTotalClasses);
        }
    

    2.1 read_images

    • read_images的内部,通过定义个静态变量doneOnce,保证操作只做一次
    // namedClasses
            // Preoptimized classes don't go in this table.
            // 4/3 is NXMapTable's load factor
            int namedClassesSize = 
                (isPreoptimized() ? unoptimizedTotalClasses : totalClasses) * 4 / 3;
            gdb_objc_realized_classes =
                NXCreateMapTable(NXStrValueMapPrototype, namedClassesSize);
            
            allocatedClasses = NXCreateHashTable(NXPtrPrototype, 0, nil);
    
    • 当第一次执行时,会创建一张包含所有的类和元类的表gdb_objc_realized_classes,外加一张只包含已经初始化的类的表allocatedClasses
    • 具体流程如下
        // 1. 初次进入,创建两张表
        if (!doneOnce) {
            doneOnce = YES;
            /** ... */
        }
    
        // 2. 类处理
        // Discover classes. Fix up unresolved future classes. Mark bundle classes.
        for (EACH_HEADER) {...}
        ts.log("IMAGE TIMES: discover classes");
    
        // Fix up remapped classes
        // Class list and nonlazy class list remain unremapped.
        // Class refs and super refs are remapped for message dispatching.
        
        if (!noClassesRemapped()) {
            for (EACH_HEADER) {...}
        }
    
        ts.log("IMAGE TIMES: remap classes");
    
        
        // 3. 方法编号处理
        // Fix up @selector references
        for (EACH_HEADER) {...}
        ts.log("IMAGE TIMES: fix up selector references");
    
        
        // 修复处理,一般不会走
    #if SUPPORT_FIXUP
        // Fix up old objc_msgSend_fixup call sites
        for (EACH_HEADER) {...}
        ts.log("IMAGE TIMES: fix up objc_msgSend_fixup");
    #endif
    
        // 4. 协议处理
        // Discover protocols. Fix up protocol refs.
        for (EACH_HEADER) {...}
        ts.log("IMAGE TIMES: discover protocols");
    
        // 修复处理,忽略
        // Fix up @protocol references
        // Preoptimized images may have the right 
        // answer already but we don't know for sure.
        for (EACH_HEADER) {...}
        ts.log("IMAGE TIMES: fix up @protocol references");
    
        // 5. 非懒加载类的处理
        // Realize non-lazy classes (for +load methods and static instances)
        for (EACH_HEADER) {...}
        ts.log("IMAGE TIMES: realize non-lazy classes");
    
        // 6. 将来需要处理的类
        // Realize newly-resolved future classes, in case CF manipulates them
        if (resolvedFutureClasses) {...}
        ts.log("IMAGE TIMES: realize future classes");
    
        // 7. 分类处理
        // Discover categories. 
        for (EACH_HEADER) {...}
        ts.log("IMAGE TIMES: discover categories");
    

    2.2 类的处理

    2.2.1 分析
    • 那么再回到 read_images中,当创建完两张表之后,会进行类的处理,那么现在来分析一下,具体的处理过程
    • 1.首先遍历当前的classlist,获取一下当前的类cls,此时只能获取到一个占位空间,没有具体信息
    • 2.通过readClass读取cls的信息,读取完之后赋值给newCls,此时拿到了类的相关信息
            for (i = 0; i < count; i++) {
                //数组中会取出OS_dispatch_queue_concurrent、OS_xpc_object、NSRunloop等系统类,例如CF、Fundation、libdispatch中的类。 以及自己创建的类,
                //此时只有地址,还没有获取到具体的类名,类的信息在下一步获取
                Class cls = (Class)classlist[i];
                
                // 通过readClass函数获取处理后的新类,
                Class newCls = readClass(cls, headerIsBundle, headerIsPreoptimized);
    
                // 初始化所有懒加载的类需要的内存空间 - 现在数据没有加载到的 - 连类都没有初始化的
                if (newCls != cls  &&  newCls) {
                    // Class was moved but not deleted. Currently this occurs 
                    // only when the new class resolved a future class.
                    // Non-lazily realize the class below.
    
                    // 将懒加载的类添加到数组中
                    resolvedFutureClasses = (Class *)
                        realloc(resolvedFutureClasses, 
                                (resolvedFutureClassCount+1) * sizeof(Class));
                    resolvedFutureClasses[resolvedFutureClassCount++] = newCls;
                }
            }
    
    2.2.2 readClass初步分析
    • 进入到readClass内部,我们可以看到如下代码,包含了class的rw以及ro等等赋值,我们的第一反应就是在readClass的时候进行rw和ro的读取
     Class replacing = nil;
        if (Class newCls = popFutureNamedClass(mangledName)) {
            // This name was previously allocated as a future class.
            // Copy objc_class to future class's struct.
            // Preserve future's rw data block.
            printf("******** popFutureNamedClass \n");
            
            if (newCls->isAnySwift()) {
                _objc_fatal("Can't complete future class request for '%s' "
                            "because the real class is too big.", 
                            cls->nameForLogging());
            }
            
            class_rw_t *rw = newCls->data();
            const class_ro_t *old_ro = rw->ro;
            memcpy(newCls, cls, sizeof(objc_class));
            rw->ro = (class_ro_t *)newCls->data();
            newCls->setData(rw);
            freeIfMutable((char *)old_ro->name);
            free((void *)old_ro);
            
            addRemappedClass(cls, newCls);
            
            replacing = cls;
            cls = newCls;
        }
    
    • 那么我们手动试验一下,先在if内部增加一个打印方法
    printf("******** popFutureNamedClass \n");
    
    • 为了更准确知道到底有没有在这里进行赋值,我们在判断之前,先用一段代码打印一下加载的类的信息
    // 验证方式, 这段代码放在上面那段 上面执行
        const class_ro_t *lgro = (const class_ro_t *)cls->data();
        const char *lgname     = lgro->name;
        const char *lgnameTest = "LGPerson";
        if (strcmp(lgname, lgnameTest) == 0) {
            printf("******** LGPerson\n");
        }
    
    • 看一下输出结果,popFutureNamedClass没有被打印,LGPerson被打印出来,可以发现当我们自定义的类LGPerson被加载的时候,并没有走到方法内部,而系统类也没有走到该方法内部,也就是说不满足popFutureNamedClass的条件,所以基本可以确定,一般的类不会在这里进行操作,这里是专门针对未来的待处理的类的特殊操作
    ******** LGPerson
    2020-01-09 23:16:22.008399+0800 objc-debug[4032:140200] +[LGTeacher load]
    2020-01-09 23:16:22.008904+0800 objc-debug[4032:140200] +[LGStudent load]
    
    2.2.3 readClass进一步探索
    • 我们知道普通的类并不会走到上面的if条件内部,那么接着看下面,其中在else中出现了两个方法addNamedClassaddClassTableEntry,分别追踪其方法内部,
    if (headerIsPreoptimized  &&  !replacing) {
            // class list built in shared cache
            // fixme strict assert doesn't work because of duplicates
            // assert(cls == getClass(name));
            assert(getClassExceptSomeSwift(mangledName));
        } else {
            addNamedClass(cls, mangledName, replacing);
            addClassTableEntry(cls);
        }
    
    • addNamedClass是把当前类cls添加到总表gdb_objc_realized_classes中去
    /***********************************************************************
    * addNamedClass
    * Adds name => cls to the named non-meta class map.
    * Warns about duplicate class names and keeps the old mapping.
    * Locking: runtimeLock must be held by the caller
    **********************************************************************/
    static void addNamedClass(Class cls, const char *name, Class replacing = nil)
    {
        runtimeLock.assertLocked();
        Class old;
        if ((old = getClassExceptSomeSwift(name))  &&  old != replacing) {
            inform_duplicate(name, old, cls);
    
            // getMaybeUnrealizedNonMetaClass uses name lookups.
            // Classes not found by name lookup must be in the
            // secondary meta->nonmeta table.
            addNonMetaClass(cls);
        } else {
            NXMapInsert(gdb_objc_realized_classes, name, cls);
        }
        assert(!(cls->data()->flags & RO_META));
    
        // wrong: constructed classes are already realized when they get here
        // assert(!cls->isRealized());
    }
    
    • addClassTableEntry是把当前类cls添加到,已经分配好的类的表allocatedClasses
    /***********************************************************************
    * addClassTableEntry
    * Add a class to the table of all classes. If addMeta is true,
    * automatically adds the metaclass of the class as well.
    * Locking: runtimeLock must be held by the caller.
    **********************************************************************/
    static void addClassTableEntry(Class cls, bool addMeta = true) {
        runtimeLock.assertLocked();
    
        // This class is allowed to be a known class via the shared cache or via
        // data segments, but it is not allowed to be in the dynamic table already.
        assert(!NXHashMember(allocatedClasses, cls));
    
        if (!isKnownClass(cls))
            NXHashInsert(allocatedClasses, cls);
        if (addMeta)
            addClassTableEntry(cls->ISA(), false);
    }
    
    • 到此,当前类cls已经通过readClass被成功插入到两张表中
    2.2.4 readClass延伸
    • readClass之后,我们拿到了一个被处理后的新的类newCls,当newClscls不相同之后就会走特殊处理
    • 但是通过刚才readClass我们可以知道,一般的系统类和自定义类走完方法之后并没有改变,只有当有符合popFutureNamedClass条件的类出现的时候,我们才会走特殊的if处理方法,并且在最后给cls赋值,cls = newCls(代码可以看2.2.2第一段代码最后),所以外面这个if判断,对于一般类来说是肯定不会走的
    Class newCls = readClass(cls, headerIsBundle, headerIsPreoptimized);
    // 初始化所有懒加载的类需要的内存空间 - 现在数据没有加载到的 - 连类都没有初始化的
    if (newCls != cls  &&  newCls) {
        // Class was moved but not deleted. Currently this occurs 
        // only when the new class resolved a future class.
        // Non-lazily realize the class below.
    
        // 将懒加载的类添加到数组中
        resolvedFutureClasses = (Class *)
            realloc(resolvedFutureClasses, 
                    (resolvedFutureClassCount+1) * sizeof(Class));
        resolvedFutureClasses[resolvedFutureClassCount++] = newCls;
    }       
    

    2.3 方法编号和协议处理

    • 通过_getObjc2SelectorRefs读取所有的方法,并且把名字注册到当前的内存中去
    • 遍历所有协议列表,并且将协议列表加载到Protocol的哈希表中
    // 将所有SEL都注册到哈希表中,是另外一张哈希表
        // Fix up @selector references
        static size_t UnfixedSelectors;
        {
            mutex_locker_t lock(selLock);
            for (EACH_HEADER) {
                if (hi->isPreoptimized()) continue;
                
                bool isBundle = hi->isBundle();
                SEL *sels = _getObjc2SelectorRefs(hi, &count);
                UnfixedSelectors += count;
                for (i = 0; i < count; i++) {
                    const char *name = sel_cname(sels[i]);
                    // 注册SEL的操作
                    sels[i] = sel_registerNameNoLock(name, isBundle);
                }
            }
        }
    // Discover protocols. Fix up protocol refs.
        // 遍历所有协议列表,并且将协议列表加载到Protocol的哈希表中
        for (EACH_HEADER) {
            extern objc_class OBJC_CLASS_$_Protocol;
            // cls = Protocol类,所有协议和对象的结构体都类似,isa都对应Protocol类
            Class cls = (Class)&OBJC_CLASS_$_Protocol;
            assert(cls);
            // 获取protocol哈希表
            NXMapTable *protocol_map = protocols();
            bool isPreoptimized = hi->isPreoptimized();
            bool isBundle = hi->isBundle();
    
            // 从编译器中读取并初始化Protocol
            protocol_t **protolist = _getObjc2ProtocolList(hi, &count);
            for (i = 0; i < count; i++) {
                readProtocol(protolist[i], cls, protocol_map, 
                             isPreoptimized, isBundle);
            }
        }
    

    2.4 非懒加载类的处理

      1. 针对非懒加载的类的处理,还是先从镜像表中映射出来cls后,然后进行一些isa和cache的初始化赋值
      1. 再次插入到表allocatedClasses中
      1. realizeClassWithoutSwift实现所有非懒加载的类(实例化类对象的一些信息,例如rw)
        // 实现非懒加载的类,对于load方法和静态实例变量
        for (EACH_HEADER) {
            classref_t *classlist = 
                _getObjc2NonlazyClassList(hi, &count);
            for (i = 0; i < count; i++) {
                // 从镜像列表中映射出来
                Class cls = remapClass(classlist[i]);
                // printf("non-lazy Class:%s\n",cls->mangledName());
                if (!cls) continue;
    
                // hack for class __ARCLite__, which didn't get this above
    #if TARGET_OS_SIMULATOR
                if (cls->cache._buckets == (void*)&_objc_empty_cache  &&  
                    (cls->cache._mask  ||  cls->cache._occupied)) 
                {
                    cls->cache._mask = 0;
                    cls->cache._occupied = 0;
                }
                if (cls->ISA()->cache._buckets == (void*)&_objc_empty_cache  &&  
                    (cls->ISA()->cache._mask  ||  cls->ISA()->cache._occupied)) 
                {
                    cls->ISA()->cache._mask = 0;
                    cls->ISA()->cache._occupied = 0;
                }
    #endif
                // 再次插入到表allocatedClasses中
                addClassTableEntry(cls);
    
                if (cls->isSwiftStable()) {
                    if (cls->swiftMetadataInitializer()) {
                        _objc_fatal("Swift class %s with a metadata initializer "
                                    "is not allowed to be non-lazy",
                                    cls->nameForLogging());
                    }
                    // fixme also disallow relocatable classes
                    // We can't disallow all Swift classes because of
                    // classes like Swift.__EmptyArrayStorage
                }
                // 实现所有非懒加载的类(实例化类对象的一些信息,例如rw)
                realizeClassWithoutSwift(cls);
            }
        }
    
    2.4.1 realizeClassWithoutSwift
    • 进入到方法内部,可以看到ro的赋值,此时ro已经有了值,但是rw只是创建,并没有值
        ro = (const class_ro_t *)cls->data();
        if (ro->flags & RO_FUTURE) {
            // 针对未来的类的特殊处理,不在主线流程中
            // This was a future class. rw data is already allocated.
            rw = cls->data();
            ro = cls->data()->ro;
            cls->changeInfo(RW_REALIZED|RW_REALIZING, RW_FUTURE);
        } else {
            // Normal class. Allocate writeable class data.
            // 一般的普通类都走这里,
            rw = (class_rw_t *)calloc(sizeof(class_rw_t), 1);
            rw->ro = ro;
            rw->flags = RW_REALIZED|RW_REALIZING;
            cls->setData(rw);
        }
    
    • 继续往下,通过类的继承链,不断往上级父类递归处理,直到cls为nil的时候,则递归中断退出,从之前的isa和superClass继承图上,我们可以了解到,NSObject的父类为nil,那么刚好,这个递归,一直找到继承链的顶端也就是NSObject为止
    if (!cls) return nil;
    ...
    supercls = realizeClassWithoutSwift(remapClass(cls->superclass));
    metacls = realizeClassWithoutSwift(remapClass(cls->ISA()));
    
    cls->superclass = supercls;
    cls->initClassIsa(metacls);
    
    2.4.2 methodizeClass
    • realizeClassWithoutSwift方法即将返回之前,我们可以看到,系统还调用了methodizeClass方法
    static Class realizeClassWithoutSwift(Class cls)
    {
      // 都是代码
    
        // Attach categories
        methodizeClass(cls);
        return cls;
    }
    
    
    • methodizeClass通过attachLists将methods、properties以及protocols写入到rw对应的位置上去
        // Install methods and properties that the class implements itself.
        method_list_t *list = ro->baseMethods();
        if (list) {
            prepareMethodLists(cls, &list, 1, YES, isBundleClass(cls));
            rw->methods.attachLists(&list, 1);
        }
    
        property_list_t *proplist = ro->baseProperties;
        if (proplist) {
            rw->properties.attachLists(&proplist, 1);
        }
    
        protocol_list_t *protolist = ro->baseProtocols;
        if (protolist) {
            rw->protocols.attachLists(&protolist, 1);
        }
    
    • 这里需要介绍一下attachLists的实现,通过把oldList向后偏移addedCount的位置,然后把新的addedLists整体插入到表的前面,从而实现分类的方法覆盖本类同名方法
        void attachLists(List* const * addedLists, uint32_t addedCount) {
            if (addedCount == 0) return;
    
            if (hasArray()) {
                // many lists -> many lists
                uint32_t oldCount = array()->count;//10
                uint32_t newCount = oldCount + addedCount;//4
                setArray((array_t *)realloc(array(), array_t::byteSize(newCount)));
                array()->count = newCount;// 10+4
       
                memmove(array()->lists + addedCount, array()->lists,
                        oldCount * sizeof(array()->lists[0]));
                
                memcpy(array()->lists, addedLists, 
                       addedCount * sizeof(array()->lists[0]));
            }
            else if (!list  &&  addedCount == 1) {
                // 0 lists -> 1 list
                list = addedLists[0];
            } 
            else {
                // 1 list -> many lists
                List* oldList = list;
                uint32_t oldCount = oldList ? 1 : 0;
                uint32_t newCount = oldCount + addedCount;
                setArray((array_t *)malloc(array_t::byteSize(newCount)));
                array()->count = newCount;
                if (oldList) array()->lists[addedCount] = oldList;
                memcpy(array()->lists, addedLists, 
                       addedCount * sizeof(array()->lists[0]));
            }
        }
    
    • 到此,非懒加载类的rw也已经赋值完成

    2.5 懒加载类的处理

    • 没有实现load方法的类,叫做懒加载类
    • 当懒加载类第一次调用消息发送的时候,会去实现该类
    • lookUpImpOrForward方法中,当isRealized条件满足时,会去调用方法realizeClassMaybeSwiftAndLeaveLocked
    • 最后调用realizeClassWithoutSwift(cls)和之前类似处理
    if (!cls->isRealized()) {
            cls = realizeClassMaybeSwiftAndLeaveLocked(cls, runtimeLock);
            // runtimeLock may have been dropped but is now locked again
    }
    
    static Class
    realizeClassMaybeSwiftAndLeaveLocked(Class cls, mutex_t& lock)
    {
        return realizeClassMaybeSwiftMaybeRelock(cls, lock, true);
    }
    
    static Class
    realizeClassMaybeSwiftMaybeRelock(Class cls, mutex_t& lock, bool leaveLocked)
    {
        lock.assertLocked();
    
        if (!cls->isSwiftStable_ButAllowLegacyForNow()) {
            // Non-Swift class. Realize it now with the lock still held.
            // fixme wrong in the future for objc subclasses of swift classes
            realizeClassWithoutSwift(cls);
            if (!leaveLocked) lock.unlock();
        } else {
            // Swift class. We need to drop locks and call the Swift
            // runtime to initialize it.
            lock.unlock();
            cls = realizeSwiftClass(cls);
            assert(cls->isRealized());    // callback must have provoked realization
            if (leaveLocked) lock.lock();
        }
    
        return cls;
    }
    

    2.6 分类的处理

    2.6.1 分类的定义
    • 自定义分类LGTeacher+test,反编译成C++文件以后,发现分类结构体
    struct _category_t {
        const char *name; // 谁的分类
        struct _class_t *cls; // 类
        const struct _method_list_t *instance_methods;
        const struct _method_list_t *class_methods;
        const struct _protocol_list_t *protocols;
        const struct _prop_list_t *properties;
    };
    
    • 在objc源码中objc-runtime-new.h里面定义到分类结构体
    struct category_t {
        const char *name;
        classref_t cls;
        struct method_list_t *instanceMethods;
        struct method_list_t *classMethods;
        struct protocol_list_t *protocols;
        struct property_list_t *instanceProperties;
        // Fields below this point are not always present on disk.
        struct property_list_t *_classProperties;
    
        method_list_t *methodsForMeta(bool isMeta) {
            if (isMeta) return classMethods;
            else return instanceMethods;
        }
    
        property_list_t *propertiesForMeta(bool isMeta, struct header_info *hi);
    };
    
    2.6.2 分类的加载
    2.6.2.1 非懒加载主类+非懒加载分类
    • 1.read_images
    • 2.realizeClassWithoutSwift
    • 3.methodizeClass(cls)
    • 4.unattachedCategoriesForClass
    • 5.attachCategories
    2.6.2.2 非懒加载主类+懒加载分类
    • 1.read_images
    • 2.realizeClassWithoutSwift
    • 3.methodizeClass(cls)
    • 4.直接添加到data->ro
    2.6.2.3 懒加载主类+懒加载分类
    • 1.ObjcMsgSend
    • 2.lookuporforward
    • 3.realizeClassWithoutSwift
    • 4.methodlizeClass
    2.6.2.4 懒加载主类+非懒加载分类
    • 这个时候,主类需要提前实现
    • 提前到prepare_load_methods实现

    3. 总结

    • 1._objc_init先进行初始化设置
    • 2.通知进行map_images,其中关键操作就是read_images
    • 3.read_images内部先把类添加到表gdb_objc_realized_classesallocatedClasses中去,之后把方法编号和协议等也映射到内存中去,并在对非懒加载类进行处理的时候,通过realizeClassWithoutSwiftro进行赋值,并且创建rw,之后通过methodizeClassrw赋值
    • 4.对于懒加载类处理的时候,则是在第一次消息发送的时候进行处理
    • 5.对于分类的处理的时候,需要考虑到主类和分类是否分别为懒加载类,需要分开处理,当分类为懒加载类时,编译时就确定,如果为非懒加载分类,那么就是运行时确定,
    • 这一块理解的有点迷~~~,有错误的地方希望大家补充指正

    相关文章

      网友评论

        本文标题:iOS底层原理之类的加载处理

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