Call rules for load
- The load method of a class is called after all the load method calls of its parent class
- The load method of the class is called after the load method of the current class is called
- The order in which the load methods of a class are called depends on the order in which they are compiled
explore
Just as in the previous article you explored the underlying principles of categories by hand, open the objc source code directly and proceed to the _objc_init function
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);
}
Copy the code
- The previously mentioned
load_images
It is dyLD that initializes the loading image method, so it should be explored this time
void
load_images(const char *path __unused, const struct mach_header *mh)
{
// Return without taking locks if there are no +load methods here.
if(! hasLoadMethods((const headerType *)mh)) return;
recursive_mutex_locker_t lock(loadMethodLock);
// Discover load methods
{
mutex_locker_t lock2(runtimeLock);
/ * * * /
prepare_load_methods((const headerType *)mh);
}
// Call +load methods (without runtimeLock - re-entrant)
call_load_methods();
}
Copy the code
- We found what we were looking for
load
Method, first to exploreprepare_load_methods
What did you do? I’ll see it latercall_load_methods
void prepare_load_methods(const headerType *mhdr)
{
size_t count, i;
runtimeLock.assertLocked();
Load the list of classes from the Macho file
classref_t *classlist =
_getObjc2NonlazyClassList(mhdr, &count);
for (i = 0; i < count; i++) {
// Array: [< CLS,method>,< CLS,method>,< CLS,method>
schedule_class_load(remapClass(classlist[i]));
}
// For the classification of operations!
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 classrealizeClass(cls); assert(cls->ISA()->isRealized()); add_category_to_loadable_list(cat); }}Copy the code
getObjc2NonlazyClassList
fromMach-O
The file retrieves a list of classes that are not lazily loaded, then loops through the list of classes, calling a recursive methodschedule_class_load
- Take a look at
schedule_class_load
What did
schedule_class_load
Call the parent class recursively, all the way up to the parent class and call it, so this demonstrates our first conclusion at the beginning of this article:The load method of a class is called after all the load method calls of its parent class- So let’s see
add_class_to_loadable_list
- Back outside
// For the classification of operations!
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
realizeClass(cls);
assert(cls->ISA()->isRealized());
add_category_to_loadable_list(cat);
}
Copy the code
-
It can be seen that the classification is also a non-lazy load classification obtained from the Mach-O file. It is verified that the call order of the load method of the classification is related to the compile order, and the load method is called in different order
-
Add_category_to_loadable_list what does this method do
-
This is similar to add_class_to_loadable_list above, except that it is loaded into the global container of the classification
-
Now that we’re done exploring prepare_load_methods, let’s go back and see what call_load_methods does
-
The load method of the class is called after the load method of the current class
-
Call_class_loads is called by SEL of load
-
Call_category_loads similarly