preface
In the last blog we solved the loading of classes, this time we’ll explore how categories load.
Structure of classification
- new
QHPerson+QHA
Sort, then runclang -rewrite-objc QHPerson+QHA.m -o QHPerson+QHA.cpp
Command, getQHPerson+QHA.cpp
file
2. In the code found the actual category is also the structure category_t
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;
};
Copy the code
Name: indicates the name of the category, such as QHA, and CLS indicates the associated class. There are instance methods, class methods, protocols, properties.
When is RWE initialized
As you know from the last blog, loading a category calls the attachCategories method, but rWE must be present before loading:
在attachCategories
We also find the initialization method incls->data()->extAllocIfNeeded()
. This is called before adding a category.
extension
In addition to adding classes, when will rWE also be initialized? Global search for extAllocIfNeeded in source code, find dynamic add methods, protocols, attributes, will be initialized. # Analysis of attachLists algorithm
void attachLists(List* **const** * addedLists, uint32_t addedCount) {
if (addedCount == 0) return;
if (hasArray()) {
// many lists -> many lists
uint32_t oldCount = array()->count;
uint32_t newCount = oldCount + addedCount;
array_t *newArray = (array_t *)malloc(array_t: :byteSize(newCount));
newArray->count = newCount;
array()->count = newCount;
for (int i = oldCount - 1; i >= 0; i--)
newArray->lists[i + addedCount] = array()->lists[i];
for (unsigned i = 0; i < addedCount; i++)
newArray->lists[i] = addedLists[i];
free(array());
setArray(newArray);
validate(a); }else if(! list && addedCount ==1) {
// 0 lists -> 1 list
list = addedLists[0];
validate(a); }else {
// 1 list -> many lists
Ptr<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;
for (unsigned i = 0; i < addedCount; i++)
array()->lists[i] = addedLists[i];
validate();
}
}
Copy the code
- There are three cases of this algorithm
- The first time if the main class has no methods, then the methods of the class are added between them
- If the main class has methods and only one category, don’t put the methods of the main class last and let the methods of the category be inserted first
- If there are more than one classification, the previous method is put into the array and the new classification method is inserted in front of it.
Classification methods and main class methods are arranged as follows:
The loading condition of classification is analyzed in different cases
The following are different cases: does the main class and classification have a combination of load methods to explore? When was the classification method added to the methods
1. Load is the main class and load is the category
Add a breakpoint to the realizeClassWithoutSwift method:
foundro
There’s no sorting method in there, so the stack will change and it will passload_images->loadAllCategories->load_categories_nolock->attachCategories
Such a process adds classification
2. The main class has load, but the classification does not have load
Tracing breakpoint debugging: realizeClassWithoutSwift->methodizeClass->attachToClass does not call the method that adds the class
RealizeClassWithoutSwift check the ro method data:
3. The main class has no load, but the classification has load
Tracing breakpoint debugging: realizeClassWithoutSwift->methodizeClass->attachToClass does not call the method that adds the class
Repeat the operation of 2 and find that, like 2, the classification data has been added at the compile stage
4. There is no load for the main class and no load for the classification
I entered main directly, and all breakpoints did not goThen continue:
It is called when a message is found to be sentrealizeClassWithoutSwift
Method to print the value of ro, and found that there are also methods for classification and classes.
conclusion
According to the analysis of the above several cases, the classification loading is divided into different cases. Whether the main class and classification implement the load method will affect the classification loading time. In general, if we have too many load methods in the classification, it will affect the speed of dyld startup. We minimize the need to add load methods to main classes and classifications if necessary. Wait until the program starts to load lazily.