12-ios底层-类的加载原理上

1,099 阅读11分钟

objc-init分析

image.png 分别调用了很多方法分别是:

  • environ_init() : 读取影响运⾏时的环境变量。如果需要,还可以打印环境变量帮助。
  • tls_init():关于线程key的绑定 - ⽐如每线程数据的析构函数
  • static_init() :运⾏C ++静态构造函数。在dyld调⽤我们的静态构造函数之前,libc 会调⽤_objc_init(),因此我们必须⾃⼰做
  • lock_init(): 没有重写,采⽤C++的特性
  • exception_init() 初始化libobjc的异常处理系统
  • cache_init(): 缓存条件初始化
  • runtime_init() : runtime运⾏时环境初始化,⾥⾯主要是:unattachedCategories,allocatedClasses 后⾯会分析
  • _imp_implementationWithBlock_init :启动回调机制。通常这不会做什么,因为所有的初始化都 是惰性的,但是对于某些进程,我们会迫不及待地加载trampolines dylib。

environ_init(); 读取影响运行时的环境变量。如果需要,还可以打印环境变量帮助。

    1. 进入 void environ_init(void)源码查看
void environ_init(void) 
{
...
    //这段代码是下面代码的复制,同时删除判断。运行后。
    for (size_t i = 0; i < sizeof(Settings)/sizeof(Settings[0]); i++) {

        const option_t *opt = &Settings[i];

        _objc_inform("%s: %s", opt->env, opt->help);

        _objc_inform("%s is set", opt->env);

    }
    ...
    // Print OBJC_HELP and OBJC_PRINT_OPTIONS output.

    if (PrintHelp  ||  PrintOptions) {

        if (PrintHelp) {

            _objc_inform("Objective-C runtime debugging. Set variable=YES to enable.");

            _objc_inform("OBJC_HELP: describe available environment variables");

            if (PrintOptions) {

                _objc_inform("OBJC_HELP is set");

            }

            _objc_inform("OBJC_PRINT_OPTIONS: list which options are set");

        }

        if (PrintOptions) {

            _objc_inform("OBJC_PRINT_OPTIONS is set");

        }

        for (size_t i = 0; i < sizeof(Settings)/sizeof(Settings[0]); i++) {

            const option_t *opt = &Settings[i];            

            if (PrintHelp) _objc_inform("%s: %s", opt->env, opt->help);

            if (PrintOptions && *opt->var) _objc_inform("%s is set", opt->env);

        }

    }
...
}

  • 会有很多的数据打印,同时有这个 OBJC_DISABLE_NONPOINTER_ISA is set image.png
  • OBJC_DISABLE_NONPOINTER_ISA is set 这个就是isa-联合体中第一位的设置。

  • 测试一下这个设置与不设置的差别
    • 1.创建一个对象,打上断点
    • 2.x/4gx p 打印对象的内存地址,以8字节的形式输出4段
    • 3.p/t 0x011d8001000082d1 以2进制的输出p对象的isa的首地址 image.png
  • 修改环境变量 image.png
  • 运行打印
  • 发现没有OBJC_DISABLE_NONPOINTER_ISA is set打印了同时 p的isa的末尾也是0,说明这个isa-已经是一个纯的isa,不再是联合体了 image.png

  • 现在来测试下这个JC_PRINT_LOAD_METHODS,勾选。
  • load方法浪费性能。 image.png
  • 打印出哪些类中调用了load方法。 image.png
  • 就可以对这个类进行优化。 image.png

  • 现在发现原来在这个环境变量设置下能完成很多事情,现在我想知道其他的变量设置,但是有不知道是什么时。
  • 1.打开终端
  • 2.第一个指令 export OBJC_HELP=1                             
  • 3.第二个指令 /Applications/Safari.app/Contents/MacOS/Safari
  • 回车后会有很多的打印环境变量设置和注释
Objective-C runtime debugging. Set variable=YES to enable.

objc[1591]: OBJC_HELP: describe available environment variables

objc[1591]: OBJC_PRINT_OPTIONS: list which options are set

objc[1591]: OBJC_PRINT_IMAGES: log image and library names as they are loaded

objc[1591]: OBJC_PRINT_IMAGE_TIMES: measure duration of image loading steps

objc[1591]: OBJC_PRINT_LOAD_METHODS: log calls to class and category +load methods

objc[1591]: OBJC_PRINT_INITIALIZE_METHODS: log calls to class +initialize methods

objc[1591]: OBJC_PRINT_RESOLVED_METHODS: log methods created by +resolveClassMethod: and +resolveInstanceMethod:

objc[1591]: OBJC_PRINT_CLASS_SETUP: log progress of class and category setup

objc[1591]: OBJC_PRINT_PROTOCOL_SETUP: log progress of protocol setup

objc[1591]: OBJC_PRINT_IVAR_SETUP: log processing of non-fragile ivars

objc[1591]: OBJC_PRINT_VTABLE_SETUP: log processing of class vtables

objc[1591]: OBJC_PRINT_VTABLE_IMAGES: print vtable images showing overridden methods

objc[1591]: OBJC_PRINT_CACHE_SETUP: log processing of method caches

objc[1591]: OBJC_PRINT_FUTURE_CLASSES: log use of future classes for toll-free bridging

objc[1591]: OBJC_PRINT_PREOPTIMIZATION: log preoptimization courtesy of dyld shared cache

objc[1591]: OBJC_PRINT_CXX_CTORS: log calls to C++ ctors and dtors for instance variables

objc[1591]: OBJC_PRINT_EXCEPTIONS: log exception handling

objc[1591]: OBJC_PRINT_EXCEPTION_THROW: log backtrace of every objc_exception_throw()

objc[1591]: OBJC_PRINT_ALT_HANDLERS: log processing of exception alt handlers

objc[1591]: OBJC_PRINT_REPLACED_METHODS: log methods replaced by category implementations

objc[1591]: OBJC_PRINT_DEPRECATION_WARNINGS: warn about calls to deprecated runtime functions

objc[1591]: OBJC_PRINT_POOL_HIGHWATER: log high-water marks for autorelease pools

objc[1591]: OBJC_PRINT_CUSTOM_CORE: log classes with custom core methods

objc[1591]: OBJC_PRINT_CUSTOM_RR: log classes with custom retain/release methods

objc[1591]: OBJC_PRINT_CUSTOM_AWZ: log classes with custom allocWithZone methods

objc[1591]: OBJC_PRINT_RAW_ISA: log classes that require raw pointer isa fields

objc[1591]: OBJC_DEBUG_UNLOAD: warn about poorly-behaving bundles when unloaded

objc[1591]: OBJC_DEBUG_FRAGILE_SUPERCLASSES: warn about subclasses that may have been broken by subsequent changes to superclasses

objc[1591]: OBJC_DEBUG_NIL_SYNC: warn about @synchronized(nil), which does no synchronization

objc[1591]: OBJC_DEBUG_NONFRAGILE_IVARS: capriciously rearrange non-fragile ivars

objc[1591]: OBJC_DEBUG_ALT_HANDLERS: record more info about bad alt handler use

objc[1591]: OBJC_DEBUG_MISSING_POOLS: warn about autorelease with no pool in place, which may be a leak

objc[1591]: OBJC_DEBUG_POOL_ALLOCATION: halt when autorelease pools are popped out of order, and allow heap debuggers to track autorelease pools

objc[1591]: OBJC_DEBUG_DUPLICATE_CLASSES: halt when multiple classes with the same name are present

objc[1591]: OBJC_DEBUG_DONT_CRASH: halt the process by exiting instead of crashing

objc[1591]: OBJC_DEBUG_POOL_DEPTH: log fault when at least a set number of autorelease pages has been allocated

objc[1591]: OBJC_DEBUG_SCRIBBLE_CACHES: scribble the IMPs in freed method caches

objc[1591]: OBJC_DISABLE_VTABLES: disable vtable dispatch

objc[1591]: OBJC_DISABLE_PREOPTIMIZATION: disable preoptimization courtesy of dyld shared cache

objc[1591]: OBJC_DISABLE_TAGGED_POINTERS: disable tagged pointer optimization of NSNumber et al.

objc[1591]: OBJC_DISABLE_TAG_OBFUSCATION: disable obfuscation of tagged pointers

objc[1591]: OBJC_DISABLE_NONPOINTER_ISA: disable non-pointer isa fields

objc[1591]: OBJC_DISABLE_INITIALIZE_FORK_SAFETY: disable safety checks for +initialize after fork

objc[1591]: OBJC_DISABLE_FAULTS: disable os faults

objc[1591]: OBJC_DISABLE_PREOPTIMIZED_CACHES: disable preoptimized caches

objc[1591]: OBJC_DISABLE_AUTORELEASE_COALESCING: disable coalescing of autorelease pool pointers

objc[1591]: OBJC_DISABLE_AUTORELEASE_COALESCING_LRU: disable coalescing of autorelease pool pointers using look back N strategy

变量名介绍备注
OBJC_PRINT_OPTIONSlist which options are set输出OBJC已设置的选项
OBJC_PRINT_IMAGESlog image and library names as they are loaded输出已load的image信息
OBJC_PRINT_LOAD_METHODSlog calls to class and category +load methods打印 Class 及 Category 的 + (void)load 方法的调用信息
OBJC_PRINT_INITIALIZE_METHODSlog calls to class +initialize methods打印 Class 的 + (void)initialize 的调用信息
OBJC_PRINT_RESOLVED_METHODSlog methods created by +resolveClassMethod and +resolveInstanceMethod:打印通过 +resolveClassMethod: 或 +resolveInstanceMethod: 生成的类方法
OBJC_PRINT_CLASS_SETUPlog progress of class and category setup打印 Class 及 Category 的设置过程
OBJC_PRINT_PROTOCOL_SETUPlog progress of protocol setup打印 Protocol 的设置过程
OBJC_PRINT_IVAR_SETUPlog processing of non-fragile ivars打印 Ivar 的设置过程
OBJC_PRINT_VTABLE_SETUPlog processing of class vtables打印 vtable 的设置过程
OBJC_PRINT_VTABLE_IMAGESprint vtable images showing overridden methods打印 vtable 被覆盖的方法
OBJC_PRINT_CACHE_SETUPlog processing of method caches打印方法缓存的设置过程
OBJC_PRINT_FUTURE_CLASSESlog use of future classes for toll-free bridging打印从 CFType 无缝转换到 NSObject 将要使用的类(如 CFArrayRef 到 NSArray * )
OBJC_PRINT_GClog some GC operations打印一些垃圾回收操作
OBJC_PRINT_PREOPTIMIZATIONlog preoptimization courtesy of dyld shared cache打印 dyld 共享缓存优化前的问候语
OBJC_PRINT_CXX_CTORSlog calls to C++ ctors and dtors for instance variables打印类实例中的 C++ 对象的构造与析构调用
OBJC_PRINT_EXCEPTIONSlog exception handling打印异常处理
OBJC_PRINT_EXCEPTION_THROWlog backtrace of every objc_exception_throw()打印所有异常抛出时的 Backtrace
OBJC_PRINT_ALT_HANDLERSlog processing of exception alt handlers打印 alt 操作异常处理
OBJC_PRINT_REPLACED_METHODSlog methods replaced by category implementations打印被 Category 替换的方法
OBJC_PRINT_DEPRECATION_WARNINGSwarn about calls to deprecated runtime functions打印所有过时的方法调用
OBJC_PRINT_POOL_HIGHWATERlog high-water marks for autorelease pools打印 autoreleasepool 高水位警告
OBJC_PRINT_CUSTOM_RRlog classes with un-optimized custom retain/release methods打印含有未优化的自定义 retain/release 方法的类
OBJC_PRINT_CUSTOM_AWZlog classes with un-optimized custom allocWithZone methods打印含有未优化的自定义 allocWithZone 方法的类
OBJC_PRINT_RAW_ISAlog classes that require raw pointer isa fields打印需要访问原始 isa 指针的类
OBJC_DEBUG_UNLOADwarn about poorly-behaving bundles when unloaded卸载有不良行为的 Bundle 时打印警告
OBJC_DEBUG_FRAGILE_SUPERCLASSESwarn about subclasses that may have been broken by subsequent changes to superclasses当子类可能被对父类的修改破坏时打印警告
OBJC_DEBUG_FINALIZERSwarn about classes that implement -dealloc but not -finalize警告实现了 -dealloc 却没有实现 -finalize 的类
OBJC_DEBUG_NIL_SYNCwarn about @synchronized(nil), which does no synchronization警告 @synchronized(nil) 调用,这种情况不会加锁
OBJC_DEBUG_NONFRAGILE_IVARScapriciously rearrange non-fragile ivars打印突发地重新布置 non-fragile ivars 的行为
OBJC_DEBUG_ALT_HANDLERSrecord more info about bad alt handler use记录更多的 alt 操作错误信息
OBJC_DEBUG_MISSING_POOLSwarn about autorelease with no pool in place, which may be a leak警告没有 pool 的情况下使用 autorelease,可能内存泄漏
OBJC_DEBUG_DUPLICATE_CLASSEShalt when multiple classes with the same name are present当出现类重名时停机
OBJC_USE_INTERNAL_ZONEallocate runtime data in a dedicated malloc zone在一个专用的 malloc 区分配运行时数据
OBJC_DISABLE_GCforce GC OFF, even if the executable wants it on强行关闭自动垃圾回收,即使可执行文件需要垃圾回收
OBJC_DISABLE_VTABLESdisable vtable dispatch关闭 vtable 分发
OBJC_DISABLE_PREOPTIMIZATIONdisable preoptimization courtesy of dyld shared cache关闭 dyld 共享缓存优化前的问候语
OBJC_DISABLE_TAGGED_POINTERSdisable tagged pointer optimization of NSNumber et al.关闭 NSNumber 等的 tagged pointer 优化
OBJC_DISABLE_NONPOINTER_ISAdisable non-pointer isa fields关闭 non-pointer isa 字段的访问
  • 上述的指令用于调试(了解)

tls_init(); 关于线程key的绑定,比如每条线程数据的析构函数

image.png

  • 如每条线程的析构函数(这里先不做说明)

static_init();

  • 运行C++静态析构函数。在dyld调用我们的静态构造函数之前,linc会调用_objc_init()因此我们必须自己做

/***********************************************************************
* static_init
* Run C++ static constructor functions.
* libc calls _objc_init() before dyld would call our static constructors, 
* so we have to do it ourselves.
 * static_init
 * 运行c++静态构造函数。
 * libc在dyld调用静态构造函数之前调用_objc_init(),
 * 所以我们必须自己做。
dyldy 会自动调用我们的库的全局静态函数,如: __attribute__((constructor)) static void libSystem_initializer
 static_init(),我们自己去调用,在_objc_init()调用之后我们自己去调用自己库中的dyly的静态方法。
**********************************************************************/
static void static_init()
{
    size_t count;
    auto inits = getLibobjcInitializers(&_mh_dylib_header, &count);
    for (size_t i = 0; i < count; i++) {
        inits[i]();
    }
    auto offsets = getLibobjcInitializerOffsets(&_mh_dylib_header, &count);
    for (size_t i = 0; i < count; i++) {
        UnsignedInitializer init(offsets[i]);
        init();
    }
}
  • 主动调用了全局静态函数,即
__attribute__((constructor)) void objcFunc(){
    printf("来了 : %s \n",__func__);
}

这样写法的函数会被主动调用,然后

__attribute__((constructor))
static void
libSystem_initializer(int argc,
                      const char* argv[],
                      const char* envp[],
                      const char* apple[],
                      const struct ProgramVars* vars){
                      }
  • 就主动调用了这个方法。

  • 这样写法函数写在objc库中,才能保证 在调用_dyld_objc_notify_register(&map_images, load_images, unmap_image);函数之前,保证所有的全局静态函数的完成调用。


runtime_init();

  • runtime运⾏时环境初始化,⾥⾯主要是:unattachedCategories,allocatedClasses 后⾯会分析
  • 初始化两张表unattachedCategoriesallocatedClasses image.png

exception_init(); 初始化lib_objc的异常处理系统

  • 异常的监听初始化(暂时忽略)
/***********************************************************************
* exception_init
* Initialize libobjc's exception handling system.
* Called by map_images().
 * exception_init
 初始化libobjc的异常处理系统。
 *由map_images()调用。
**********************************************************************/
void exception_init(void)
{
    old_terminate = std::set_terminate(&_objc_terminate);
}


cache_init() 缓存条件初始化


_imp_implementationWithBlock_init :启动回调机制。通常这不会做什么,因为所有的初始化都是惰性的,但是对于某些进程,我们会迫不及待的加载trampolines dylib



  • 重点

_dyld_objc_notify_register(&map_images, load_images, unmap_image); 分析

  • map_images() dyldimage镜像文件加载到内存中会调用该函数。
  • load_images() dyld初始化所有的image镜像文件文件会调用。
  • unmap_image:将image镜像文件移除时会调用。

load_images方法其实就是调用load方法,map_image方法,&map_images是指针传递,指向是同一块实现的地址,如果有什么变化就可以第一时间知道。在dyldsNotifyObjCMapped调用的地方是在notifyBatchPartial方法中,而notifyBatchPartial方法是在registerObjCNotifiers中调用,在objc初始化注册通知时就调用了,所以是先调用map_images后调用load_images这么个函数执行顺序。

  • &map_images 地址值作为参数,即指针传递,数据同步进行变化。map_images 函数是一个不断递归的函数

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
 * map_images
 *处理由dyld映射的给定图像。映射镜像文件
 *在获取abi特定的锁后调用abi不可知代码。
 *
 *锁:写锁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 由于代码量过多非重点部分省略 ...
map_images_nolock(unsigned mhCount, const char * const mhPaths[],
                  const struct mach_header * const mhdrs[]){
                  ...
                  //重点进入这个循环调用中,开始读取镜像文件
                  if (hCount > 0) {
                     _read_images(hList, hCount, totalClasses, unoptimizedTotalClasses);
                  }
                  ...
                  }

read_images函数分析 主要完成的是以下的几个功能

  • 1、条件控制进行一次的加载
  • 2、修复预编译阶段‘@selector’的混乱问题
  • 3、错误混乱的类处理
  • 4、修复重映射一些没有被镜像文件加载进来的类
  • 5、修复一些消息
  • 6、当我们类里面有协议的时候:readProtocol
  • 7、修复没有被加载的协议
  • 8、分类处理
  • 9、类的加载处理
  • 10、没有被处理的类优化那些被侵犯的类

1.条件控制进行一次的加载 doneOnce

if (!doneOnce) {
    doneOnce = YES;
    launchTime = YES;
    ...
    ...
    // namedClasses
    // Preoptimized classes don't go in this table.
    // 4/3 is NXMapTable's load factor
    // objc::unattachedCategories.init(32);
    // objc::allocatedClasses.init(); //(生成一张被开辟alloc的表)
    
    int namedClassesSize =
        (isPreoptimized() ? unoptimizedTotalClasses : totalClasses) * 4 / 3;
    //创建了一个表(总表关于类名的表,不管是否有被实现)
    gdb_objc_realized_classes =
        NXCreateMapTable(NXStrValueMapPrototype, namedClassesSize);

    ts.log("IMAGE TIMES: first time tasks");
}
  • 加载一次下次就不会再次进入判断,第一次进来主要创建表 gbd_objc_realized_classes,这是一张关于所有类的不管是否有没有被实现都存放进入。是一张总表。
  • 主要作用是生成一张关于全部类名的总表,不管这个类是否有被实现 alloc init
  • allocatedClass.init() ,生成一张已经被开辟内存的表。

2.修复预编译阶段‘@selector’的混乱问题

    // Fix up @selector references
    // sel 名字 + 地址
    static size_t UnfixedSelectors;
    {
        mutex_locker_t lock(selLock);
        for (EACH_HEADER) {
            if (hi->hasPreoptimizedSelectors()) 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 sel = sel_registerNameNoLock(name, isBundle);
                if (sels[i] != sel) {
                    sels[i] = sel;
                }
            }
        }
    }
  • 不同的类中可能存在相同的方法,但是方法名相当地址是不同的。
  • 如:两个方法名相同,但是地址不同,需要进行局部处理。类的地址重定向。

sels[i]_getObjc2SelectorRefs是从MachO里面获取的,MachO有相对位移地址和偏移地址,selsel_registerNameNoLockdyld里面获取,dyld是链接整个程序的,所以以dyld的为准。因为方法是存放在类中,每个类中的位置是不一样的,所以方法的地址也就不一样,那么就必须对那些混乱的方法进行修复处理。

3、错误混乱的类处理

    // Discover classes. Fix up unresolved future classes. Mark bundle classes.
    //发现类。修复未解决的未来类。马克包类。
    bool hasDyldRoots = dyld_shared_cache_some_image_overridden();

    for (EACH_HEADER) {
        if (! mustReadClasses(hi, hasDyldRoots)) {
            // Image is sufficiently optimized that we need not call readClass()
            continue;
        }

        classref_t const *classlist = _getObjc2ClassList(hi, &count);

        bool headerIsBundle = hi->isBundle();
        bool headerIsPreoptimized = hi->hasPreoptimizedClasses();

        for (i = 0; i < count; i++) {
            Class cls = (Class)classlist[i];
            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;
            }
        }
    }

    ts.log("IMAGE TIMES: discover classes");
  • 清除没有清理干净的类

image.png

  • 类的地址读取加载。
  • readClass方法的作用:把类名和地址关联起来。

readClass 类的读取 现在开始研究我们自己写的类是如何加载的

/***********************************************************************
* readClass
* Read a class and metaclass as written by a compiler.
* Returns the new class pointer. This could be: 
* - cls
* - nil  (cls has a missing weak-linked superclass)
* - something else (space for this class was reserved by a future class)
*
* Note that all work performed by this function is preflighted by 
* mustReadClasses(). Do not change this function without updating that one.
*
* Locking: runtimeLock acquired by map_images or objc_readClassPair
**********************************************************************/
Class readClass(Class cls, bool headerIsBundle, bool headerIsPreoptimized)
{
    //获取类名
    const char *mangledName = cls->nonlazyMangledName();
    
    const char *LGPersonName = "LGPerson";

    if (strcmp(mangledName, LGPersonName) == 0) {
        // 普通写得类 他是如何
        printf("%s -KC: 要研究的: - %s\n",__func__,mangledName);
    }
    
    if (missingWeakSuperclass(cls)) {
        // No superclass (probably weak-linked). 
        // Disavow any knowledge of this subclass.
        if (PrintConnecting) {
            _objc_inform("CLASS: IGNORING class '%s' with "
                         "missing weak-linked superclass", 
                         cls->nameForLogging());
        }
        addRemappedClass(cls, nil);
        cls->setSuperclass(nil);
        return nil;
    }
    
    cls->fixupBackwardDeployingStableSwift();

    Class replacing = nil;
    if (mangledName != nullptr) {
        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.

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

            // Manually set address-discriminated ptrauthed fields
            // so that newCls gets the correct signatures.
            newCls->setSuperclass(cls->getSuperclass());
            newCls->initIsa(cls->getIsa());

            rw->set_ro((class_ro_t *)newCls->data());
            newCls->setData(rw);
            freeIfMutable((char *)old_ro->getName());
            free((void *)old_ro);

            addRemappedClass(cls, newCls);

            replacing = cls;
            cls = newCls;
        }
    }
    
    if (headerIsPreoptimized  &&  !replacing) {
        // class list built in shared cache
        // fixme strict assert doesn't work because of duplicates
        // ASSERT(cls == getClass(name));
        ASSERT(mangledName == nullptr || getClassExceptSomeSwift(mangledName));
    } else {
        if (mangledName) { //some Swift generic classes can lazily generate their names
            addNamedClass(cls, mangledName, replacing);
        } else {
            Class meta = cls->ISA();
            const class_ro_t *metaRO = meta->bits.safe_ro();
            ASSERT(metaRO->getNonMetaclass() && "Metaclass with lazy name must have a pointer to the corresponding nonmetaclass.");
            ASSERT(metaRO->getNonMetaclass() == cls && "Metaclass nonmetaclass pointer must equal the original class.");
        }
        addClassTableEntry(cls);
    }

    // for future reference: shared cache never contains MH_BUNDLEs
    if (headerIsBundle) {
        cls->data()->flags |= RO_FROM_BUNDLE;
        cls->ISA()->data()->flags |= RO_FROM_BUNDLE;
    }
    
    return cls;
}

  • 1.在自己写的类创建之前断点。 image.png
  • 2.写上语句判断打印并断点
const char *LGPersonName = "LGPerson";

if (strcmp(mangledName, LGPersonName) == 0) {
    // 普通写得类 他是如何
    printf("%s -KC: 要研究的: - %s\n",__func__,mangledName);
}

image.png

  • 3.打印信息提示 image.png

加载类流程

  • 1.readClass -> 这里并没有对类的ro,rw的赋值 nonlazyMangleName 获取类型
  • 2.addNameClass(cls,magleName,replacing)-> 将类型和地址关联起来
  • 3.addClassTableEntry(cls) ,在这里加载类以及元类 inset(cls)addMeta
  • 这里主要完成的是将类加入到表中,将这个类名的类以及元类插入到另一张哈希表中。这张表中的类都是初始化过的类

image.png

realizeClassWithoutSwift(cls, nil); 的分析流程

  • methodelizeClass() 相关方法的排序
  • prepareMehodList 对ro中的baseMethods()方法 方法名写入+排序

懒加载与非懒加载类 :

  • 当前类是否实现load方法,load方法会让一个类从懒加载类成为一个非懒加载类,懒加载类的好处是能够按需分配内存,节约内存。
  • 1.懒加载类情况 : 数据加载推迟到第一次消息的时候
    • lookUpImpOrForward
    • realizeClassMaybeSwiftMaybeRelock
    • realizeClassWithoutSwift
    • methodizeClass
  • 2.非懒加载类情况 : map_images的时候加载了所有类数据
    • readClass
    • _getObjc2NonlazyClassList
    • realizeClassWithoutSwift
    • methodizeClass