preface

In the last blog we solved the loading of classes, this time we’ll explore how categories load.

Structure of classification

  1. newQHPerson+QHASort, then runclang -rewrite-objc QHPerson+QHA.m -o QHPerson+QHA.cppCommand, getQHPerson+QHA.cppfile

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:

attachCategoriesWe 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
  1. The first time if the main class has no methods, then the methods of the class are added between them
  2. 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
  3. 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:

foundroThere’s no sorting method in there, so the stack will change and it will passload_images->loadAllCategories->load_categories_nolock->attachCategoriesSuch 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 sentrealizeClassWithoutSwiftMethod 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.