Objc – init analysis

A number of methods are called respectively:

  • environ_init(): Reads environment variables that affect the runtime. You can also print environment variable help if desired.
  • tls_init(): bindings for thread keys – such as destructors for per-thread data
  • static_init(): Runs the C ++ static constructor. Libc calls _objc_init () before DYLD calls our static constructor, so we have to do it ourselves
  • lock_init(): no rewrite, using C++ features
  • exception_init()Initialize libobJC’s exception handling system
  • cache_init(): Initializes the cache condition
  • runtime_init(): the runtime runtime environment initialization, it mainly: unattachedCategories, allocatedClasses later analysis
  • _imp_implementationWithBlock_init: Enables the callback mechanism. Normally that doesn’t do anything, because all the initializations, right

Is lazy, but for some processes we can’t wait to load trampolines dylib.

environ_init(); Read environment variables that affect the runtime. You can also print environment variable help if desired.

    1. Enter thevoid environ_init(void)The source code to view
void environ_init(void) 
{...// This code is a copy of the following code, while removing the judgment. After the operation.
    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); }}... }Copy the code
  • There will be a lot of data printing, and there will be this OBJC_DISABLE_NONPOINTER_ISA is set

  • OBJC_DISABLE_NONPOINTER_ISA is set This is the first value of isA-union.

  • Test the difference between this setting and not setting it
    • 1. Create an object and set a breakpoint
    • 2. X /4gx p Displays the memory address of the object, and outputs 4 segments in the form of 8 bytes
    • 3. P /t 0x011D8001000082D1 Displays the first ADDRESS of the ISA of the p object in base 2

  • Modifying environment Variables

  • Print run
  • No OBJC_DISABLE_NONPOINTER_ISA is set prints at the end of P’s ISA, indicating that the ISA – isa pure ISA and is no longer a union

  • So let’s test this JC_PRINT_LOAD_METHODS, check it.
  • The load method wastes performance.

  • Print out which classes call the load method.

  • You can optimize this class.


  • Now it turns out that a lot of things can be done with this environment variable setting. Now I want to know what other variable Settings are, but sometimes I don’t know what they are.
  • 1. Open the terminal
  • 2. First instructionexport OBJC_HELP=1                             
  • 3. Second instruction/Applications/Safari.app/Contents/MacOS/Safari
  • Enter and there will be a lot of print environment variable Settings and comments
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

Copy the code
The variable name introduce note
OBJC_PRINT_OPTIONS list which options are set Prints OBJC’s set options
OBJC_PRINT_IMAGES log image and library names as they are loaded The loaded image information is displayed
OBJC_PRINT_LOAD_METHODS log calls to class and category +load methods Prints calls to the + (void)load methods of Class and Category
OBJC_PRINT_INITIALIZE_METHODS log calls to class +initialize methods Print the call information for Class + (void)initialize
OBJC_PRINT_RESOLVED_METHODS log methods created by +resolveClassMethod and +resolveInstanceMethod: Print class methods generated by +resolveClassMethod: or +resolveInstanceMethod:
OBJC_PRINT_CLASS_SETUP log progress of class and category setup Print the Class and Category Settings
OBJC_PRINT_PROTOCOL_SETUP log progress of protocol setup Prints the Protocol setting process
OBJC_PRINT_IVAR_SETUP log processing of non-fragile ivars The Ivar setup process is displayed
OBJC_PRINT_VTABLE_SETUP log processing of class vtables Print the vtable setting process
OBJC_PRINT_VTABLE_IMAGES print vtable images showing overridden methods Print the method of overwriting vtable
OBJC_PRINT_CACHE_SETUP log processing of method caches Print the procedure for setting up the method cache
OBJC_PRINT_FUTURE_CLASSES log use of future classes for toll-free bridging Print classes that will be used for seamless conversion from CFType to NSObject (such as CFArrayRef to NSArray *)
OBJC_PRINT_GC log some GC operations Print some garbage collection operations
OBJC_PRINT_PREOPTIMIZATION log preoptimization courtesy of dyld shared cache Print the greeting before dyLD shared cache optimization
OBJC_PRINT_CXX_CTORS log calls to C++ ctors and dtors for instance variables Print the construction and destructor calls of C++ objects in class instances
OBJC_PRINT_EXCEPTIONS log exception handling Printing exception Processing
OBJC_PRINT_EXCEPTION_THROW log backtrace of every objc_exception_throw() Prints Backtrace for all exceptions thrown
OBJC_PRINT_ALT_HANDLERS log processing of exception alt handlers Abnormal processing of Alt operations
OBJC_PRINT_REPLACED_METHODS log methods replaced by category implementations Print the method to be replaced by Category
OBJC_PRINT_DEPRECATION_WARNINGS warn about calls to deprecated runtime functions Prints all obsolete method calls
OBJC_PRINT_POOL_HIGHWATER log high-water marks for autorelease pools Prints autoreleasepool high watermark warnings
OBJC_PRINT_CUSTOM_RR log classes with un-optimized custom retain/release methods Prints a class with a custom retain/release method that is not optimized
OBJC_PRINT_CUSTOM_AWZ log classes with un-optimized custom allocWithZone methods Prints a class with a custom allocWithZone method that is not optimized
OBJC_PRINT_RAW_ISA log classes that require raw pointer isa fields Print the classes that need access to the original ISA pointer
OBJC_DEBUG_UNLOAD warn about poorly-behaving bundles when unloaded Prints a warning when uninstalling misbehaving bundles
OBJC_DEBUG_FRAGILE_SUPERCLASSES warn about subclasses that may have been broken by subsequent changes to superclasses Prints a warning when a subclass may be broken by changes to its parent class
OBJC_DEBUG_FINALIZERS warn about classes that implement -dealloc but not -finalize Warning implements -dealloc but not -Finalize classes
OBJC_DEBUG_NIL_SYNC warn about @synchronized(nil), which does no synchronization Warning of @synchronized(nil) calls that do not lock
OBJC_DEBUG_NONFRAGILE_IVARS capriciously rearrange non-fragile ivars Prints the behavior of suddenly rearranging non-fragile ivars
OBJC_DEBUG_ALT_HANDLERS record more info about bad alt handler use Record more Alt operation errors
OBJC_DEBUG_MISSING_POOLS warn about autorelease with no pool in place, which may be a leak Warning: Using autoRelease without a pool may leak memory
OBJC_DEBUG_DUPLICATE_CLASSES halt when multiple classes with the same name are present Stop when a class duplication occurs
OBJC_USE_INTERNAL_ZONE allocate runtime data in a dedicated malloc zone Allocate runtime data in a dedicated MALloc area
OBJC_DISABLE_GC force GC OFF, even if the executable wants it on Forcibly turn off automatic garbage collection, even if the executable requires garbage collection
OBJC_DISABLE_VTABLES disable vtable dispatch Disable VTable distribution
OBJC_DISABLE_PREOPTIMIZATION disable preoptimization courtesy of dyld shared cache Disable the greeting before dyLD shared cache optimization
OBJC_DISABLE_TAGGED_POINTERS disable tagged pointer optimization of NSNumber et al. Disable tagged Pointer optimization for NSNumber
OBJC_DISABLE_NONPOINTER_ISA disable non-pointer isa fields Disable access to the non-pointer ISA field
  • The above instructions are used for debugging (understand)

tls_init(); Bindings for thread keys, such as destructors for each thread’s data

  • Such as the per-thread destructor (not explained here)

static_init();

  • Run the C++ static destructor. Before DYLD calls our static constructor,lincWill be called_objc_init()So we have to do it ourselves

/*********************************************************************** * static_init * Run C++ static constructor functions. * libc calls _objc_init() before dyld would call our static constructors, * static_init * run c++ static constructors. * Libc calls _objc_init() before dyld calls the static constructor, * so we have to do it ourselves. Dyldy will automatically call our library's global static functions, such as: __attribute__((constructor)) static void libSystem_initializer static_init() We call dyly's static methods in our library ourselves after _objc_init(). * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /
static void static_init(a)
{
    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();
    }
}
Copy the code
  • A global static function was actively called, i.e
__attribute__((constructor)) void objcFunc(a){
    printf("Coming: %s \n",__func__);
}
Copy the code

The function written this way will be called actively, and then

__attribute__((constructor))
static void
libSystem_initializer(int argc,
                      const char* argv[],
                      const char* envp[],
                      const char* apple[],
                      const struct ProgramVars* vars){}Copy the code
  • I call this method on my own initiative.

  • _dyLD_OBJC_notify_register (&map_images, load_images, unmap_image); Ensure that all global static functions are called before the function is called.


runtime_init();

  • The runtime runtime environment initialization, it mainly: unattachedCategories, allocatedClasses later analysis
  • Initialize two tablesunattachedCategories.allocatedClasses


exception_init(); Initialize the exception handling system for lib_objc

  • Exception listening initialization (ignored for now)
/*********************************************************************** * exception_init * Initialize libobjc's Exception handling system. * Called by map_images(). * Exception_init Initializes libobJC's exception handling system. * called by map_images(). * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /
void exception_init(void)
{
    old_terminate = std::set_terminate(&_objc_terminate);
}

Copy the code

Cache_init () Initializes the cache condition


_imp_implementationWithBlock_init: Enables the callback mechanism. Usually this doesn’t do much, because all initialization is lazy, but for some processes we can’t wait to load trampolines dylib



points

  • Focus on

_dyld_objc_notify_register(&map_images, load_images, unmap_image); Analysis of the

  • map_images() dyldwillimageThis function is called when the image file is loaded into memory.
  • load_images() dyldInitialize allimageThe image file file is called.
  • unmap_imageWill:imageCalled when the image file is removed.

Load_images calls load, map_image, &map_images is a pointer pass that points to the address of the same block. If there is any change, you can know it immediately. The place in DYLD where sNotifyObjCMapped is called is in the notifyBatchPartial method. The notifyBatchPartial method is called in the registerObjCNotifiers when objC initializes the registration notification. So map_images is called and load_images is called.

  • &map_images Address values as parameters, i.e., Pointers passed, data synchronized for change. The map_images function is a recursive function

Map_images function analysis

/*********************************************************************** * 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 * processes the given image mapped by dyLD. Map image files * invoke ABI agnostic code after acquiring an ABI specific lock. * * lock: write lock 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);
}
Copy the code
  • Map_images_nolock due to excessive code…
map_images_nolock(unsigned mhCount, const char * const mhPaths[],
                  const struct mach_header * const mhdrs[]){
                  ...
                  // focus on the loop to start reading the image file
                  if (hCount > 0) { _read_images(hList, hCount, totalClasses, unoptimizedTotalClasses); }... }Copy the code

The read_images function analysis mainly accomplishes the following functions

  • 1, condition control for a load
  • 2. Fix ‘@selector’ confusion during precompilation
  • 3. Bad, messy class handling
  • 4, fix remapping some classes that were not loaded by the image file
  • 5. Fix some messages
  • 6. When there is a protocol in our class: readProtocol
  • 7, fix the protocol that was not loaded
  • 8. Classification
  • 9. Class loading processing
  • 10. Unprocessed classes optimize those that are violated

1. Condition control to load 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(); // generate a table where alloc is opened.
    
    int namedClassesSize =
        (isPreoptimized()? unoptimizedTotalClasses : totalClasses) *4 / 3;
    // Create a table (total table table of class names, whether implemented or not)
    gdb_objc_realized_classes =
        NXCreateMapTable(NXStrValueMapPrototype, namedClassesSize);

    ts.log("IMAGE TIMES: first time tasks");
}
Copy the code
  • Load once and you will not enter the judgment again, the first time in the main create tablegbd_objc_realized_classesThis is a list of all classes that are stored in whether they are implemented or not. It’s a master list.
  • The main function is to generate a summary table of all class names, whether or not the class is implementedalloc init
  • allocatedClass.init(), generates a table that has been allocated memory.

2. Fix ‘@selector’ confusion during precompilation

    // Fix up @selector references
    // sel name + address
    static size_t UnfixedSelectors;
    {
        mutex_locker_t lock(selLock);
        for (EACH_HEADER) {
            if (hi->hasPreoptimizedSelectors()) continue;

            bool isBundle = hi->isBundle(a); 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; }}}}Copy the code
  • The same method may exist in different classes, but the method name and address are different.
  • For example, if two methods have the same name but different addresses, local processing is required. Class address redirection.

Sels [I] is _getObjc2SelectorRefs obtained from MachO, MachO has relative displacement address and offset address, sel is sel_registerNameNoLock obtained from dyLD, dyLD is linked to the whole program, so the DYLD is subject. Because methods are stored in classes, the location of each class is different, so the address of the method is different, and the messy methods must be fixed.

3. Bad, messy class handling

    // Discover classes. Fix up unresolved future classes. Mark bundle classes.
    // Discover class. Fix unresolved future classes. Mark package class.
    bool hasDyldRoots = dyld_shared_cache_some_image_overridden(a);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(a);bool headerIsPreoptimized = hi->hasPreoptimizedClasses(a);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");
Copy the code
  • Clear classes that are not cleaned up

  • Class address read load.
  • The readClass method associates the class name with the address.

Now let’s look at how our own classes are loaded

/*********************************************************************** * 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)
{
    // Get the class name
    const char *mangledName = cls->nonlazyMangledName(a);const char *LGPersonName = "LGPerson";

    if (strcmp(mangledName, LGPersonName) == 0) {
        // How does he write in general
        printf("% s-KC: To study: - %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(a); 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(a);const class_ro_t *old_ro = rw->ro(a);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(a);const class_ro_t *metaRO = meta->bits.safe_ro(a);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;
}

Copy the code
  • 1. Breakpoint before self-written classes are created.

  • 2. Write statements to judge printing and breakpoint
const char *LGPersonName = "LGPerson";

if (strcmp(mangledName, LGPersonName) == 0) {
    // How does he write in general
    printf("% s-KC: To study: - %s\n",__func__,mangledName);
}
Copy the code

  • 3. Print information

Class Loading process

  • 1.readClassNonlazyMangleName = nonlazyMangleName = nonlazyMangleName
  • 2.addNameClass(cls,magleName,replacing)-> Associate the type and address
  • 3.addClassTableEntry(cls), where the classes and metaclasses are loadedinset(cls)addMeta
  • The main thing that is done here is to add the class to the table, and to insert the class and metaclass of this class name into another hash table. The classes in this table are all initialized classes

realizeClassWithoutSwift(cls, nil); Analysis process of

  • MethodelizeClass () collates related methods
  • PrepareMehodList writes + sort to the baseMethods() method name in ro

Lazy vs. non-lazy classes:

  • The load method changes a class from a lazy-loaded class to a non-lazy-loaded class. The advantage of lazy-loaded classes is that they can allocate memory on demand and save memory.
  • Lazy loading class situation: data loading is delayed until the first message
    • lookUpImpOrForward
    • realizeClassMaybeSwiftMaybeRelock
    • realizeClassWithoutSwift
    • methodizeClass
  • 2. Non-lazy class loading: map_images loaded all class data
    • readClass
    • _getObjc2NonlazyClassList
    • realizeClassWithoutSwift
    • methodizeClass