The load method of the objC class is not a message sending mechanism, so there is no message overwriting

  • (void)load
void _objc_init(void)
{
    _dyld_objc_notify_register(&map_images, load_images, unmap_image);
}
Copy the code

Call load_images

load_images(const char *path __unused, const struct mach_header *mh) { if (! hasLoadMethods((const headerType *)mh)) return; recursive_mutex_locker_t lock(loadMethodLock); NSRecursiveLock () ¶ // A recursive lock Class is used to solve the problem of locking multiple times without deadlock. It is the same as NSRecursiveLock, but instead of being encapsulated by NSLock, C writes a Class for Runtime scenarios. { mutex_locker_t lock2(runtimeLock); prepare_load_methods((const headerType *)mh); } // Call +load methods (without runtimeLock - re-entrant) call_load_methods(); }Copy the code

After all images have been mapped to memory, the load method is loaded

  1. Prepare_load_methods: Prepare to call (load method of class and load method of class)
void prepare_load_methods(const headerType *mhdr) { size_t count, i; runtimeLock.assertLocked(); Classref_t * classList = _getObjc2NonlazyClassList(MHDR, &count); classref_t * classList = _getObjc2NonlazyClassList(MHDR); for (i = 0; i < count; I ++) {schedule_class_load(remapClass(classList [I])); / / class pointer obtained through remapClass} / / take out all the load method of classification category_t * * categorylist = _getObjc2NonlazyCategoryList (MHDR, & count); }Copy the code

1.1 schedule_class_load: If a class implements the +load method, Classref_t * classList = _getObjc2NonlazyClassList(MHDR, &count); 1.1.2. Start traversing schedule_class_load

static void schedule_class_load(Class cls) { if (! cls) return; assert(cls->isRealized()); // _read_images should realize if (cls->data()->flags & RW_LOADED) return; // Running recursively deep (superclass) always ensures that the parent class that does not call load is added to the loadable_classes array before the subclass, thus ensuring the correct order of calls. schedule_class_load(cls->superclass); Add_class_to_loadable_list (CLS); CLS ->setInfo(RW_LOADED); }Copy the code

1.1.3. Schedule_class_load (CLS – > superclass); Add_class_to_loadable_list (CLS); ‘ll come to this class of the load method list 1.2 category method of preparing _getObjc2NonlazyClassList: obtain all have the load method of class (class) category_t * * categorylist = _getObjc2NonlazyCategoryList(mhdr, &count);

Get the list of classes from section, And to remap, and realize the each class category_t * * 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 // The first initialization of a class is used to allocate read-write data space and return the real class structure realizeClass(CLS); assert(cls->ISA()->isRealized()); Add_category_to_loadable_list (cat); add_category_to_loadable_list(cat); }Copy the code

_getObjc2NonlazyCategoryList: obtain all has the load method classification (category) remapClass: none – class pointer obtained through remapClass lazy class is a very special area to remove The class list, whose properties are set in advance only in the class implemented by the load method, otherwise only the most basic data can be loaded.

RealizeClass: Realize () returns false if there is no +load method in the class, otherwise empty. Other related properties will also change, such as hasCxxCtor & hasCustomAWZ Add_category_to_loadABLE_list: into static variable array and loadable_categories

1.3 call_load_methods: call

void call_load_methods(void) { static bool loading = NO; Bool more_categories; . / / whether the related Category loadMethodLock assertLocked (); // Re-entrant calls do nothing; the outermost call will finish the job. if (loading) return; // If loading is a global static Boolean, exit loading = YES; Void *pool = objc_autoreleasePoolPush(); // Declare an autoreleasePool object. // Use push to create a new autoreleasePool object. Do {// 1. Repeatedly call load until there aren't any loads While (loadable_classes_used > 0) {call_class_loads(); } // 2. Call category +load (loads in category), this is called only ONCE, because there is no parent class in category. // But there is no guarantee that the order of calls is correct. More_categories = call_category_loads(); more_categories = call_category_loads(); // 3. Run more +loads if there are classes OR more untried categories, Until all the Class complete} while (loadable_classes_used > 0 | | more_categories); // Release the autoreleasePool object objc_autoreleasePoolPop(pool); Loading = NO; }Copy the code

Do while is a load call to class :call_class_loads(); ->static void call_class_loads(void) categories: more_categories = call_category_loads(); ->static bool call_category_loads(void)

load_method_t load_method = (load_method_t)cats[i].method; Class cls; if (! cat) continue; cls = _category_getClass(cat); if (cls && cls->isLoadable()) { if (PrintLoading) { _objc_inform("LOAD: +[%s(%s) load]\n", cls->nameForLogging(), _category_getName(cat)); } (*load_method)(cls, SEL_load); cats[i].cat = nil; }Copy the code

The get method. Direct function pointer calls function (*load_method)(CLS, SEL_load); Since the load method is not a load sending mechanism, there is no phenomenon that the load method of the class overrides the load method of the class. However, the code manually calls the load method of the class, because it is a load sending mechanism, the load method of the class will be executed first. To summarize

The call to the load method is now clear. The following three processes are sorted out:

  1. Load Images: Load the image file via dyld, importing the Class.
  2. Prepare Load Methods: Prepare Load Methods. Filter invalid classes, invalid methods, and collect the load method pointer and its owning Class pointer to the global Class store linear table loadable_classes, which involves automatic expansion space and recursive calls of the parent Class first.
  3. Call Load Methods: Dynamically invoke the Load method based on the collected function pointer. Further filter out invalid methods and log them. Load call features: • Load is called when the class is imported into the project, • it doesn’t matter if the class is used before main is executed • Load is called only once for each class • Load is automatically loaded by the system, There is no need to call the parent’s load function. • When both the parent and the child implement load, the parent’s load methods take precedence over the child’s. • The load method of a subclass will not be called if the subclass does not implement the load method. • There are multiple categories that implement load methods, all of which are executed in an uncertain order (the order in which the categories appear in Compile Sources)

[initialize]