preface
We’ve seen a lot about class loading in the previous study, but there is a special treatment to attachCategories, which is called attachCategories. So what about the loading of categories? This section mainly discusses the source code implementation structure of classification.
Ro Rw Rwe
I’ve written in detail about these differences in my previous blog # Metaclasses Underlying Exploration, where Ro exists in sandbox files, and Rw (dirty memory) is copied from Ro (clean memory), which is generated when the class is first used. The data in the sandbox is read-only, and if we want to modify it, it must be copied and stored in Rw. However, due to the objective factors of mobile phones in IOS, Rw is very different from Mac, and the memory is very tight. Therefore, Rwe is produced, which is the expansion from Rw. Optimize this part of the Rw, some of the data will not change, it is not necessary to store all of it as modifiable data. Rwe storage capacity is allocated extra at run time, for example, classification, not every class has classification, so Apple does quite a bit of optimization in this area, we put the things that don’t change in Ro, we put the things that are readable and readable in Rwe.
How to assign Rw
The system gets the address (from mach0) by shifting the pointer to the address (from mach0), and can get the value from the address (from the type it specifies).
class_rw_t *data() **const{* * * *return** bits.data();
}
Copy the code
class_rw_t* data() **const{* * * *return** (class_rw_t *)(bits & FAST_DATA_MASK);
}
Copy the code
How to assign Rwe
We already know that the RWE is obtained from the extAllocIfNeeded method of attachCategories. But what’s going on inside is still unknown. Search extAllocIfNeeded globally to find out when the rWE has been modified. Search addMethods_finish, class_addProtocol, _class_addProperty, Objc_duplicateClass is basically an assignment when you add a method protocol attribute.
When does the category load?
Backstepping!!!!!
Search globally for AttachCategories. attachToClass and load_categories_nolock prove that these two categories. continue searching for attachToClass.
We’re going to go to the separate methods, we’re going to trace the previously, we’re going to find nil, and this argument is the alternate argument. AttachToClass is called in the methodizeClass method.
graph TD
realizeClassWithoutSwift --> methodizeClass -->attachToClass-->attachCategories
attachCategories &
As you add branches, you have to look at this object that we need to look at at the end what is the implementation of this object? There is no need to dig into it, through its implementation method, which is dynamically added with the attachLists method.
Here we simply add a method
支那else* * * *if* * (! list && addedCount ==1) {
// 0 lists -> 1 list
list = addedLists[0];
validate();
}
Copy the code
First open up the old + new capacity, and then insert the old to the end, the new insert forward.
// 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
If you already have an array, another array comes in, opens up a new space array, inserts the old array in reverse order, and then inserts the new array in front.
支那if** (hasArray()) {
// many lists -> many listsuint32_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; A \ * *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();
}
Copy the code
Loading of class & classification
We already know that classes are loaded lazily. If you don’t write the load method, you won’t use the read_images method. What’s the difference between class and classification loading?
Order of loading methods
General trend
1. There are load methods for both categories and classes:
_read_images – > realizeClassWithoutSwift – > mothodizeClass – >load_categories_lock – > attachCategories
2. Load: print method for main class
_read_images – > realizeClassWithoutSwift – >mothodizeClass – > attachToClass – > attachCategories
3. Load: print method from data())
_read_images – > realizeClassWithoutSwift – >mothodizeClass – > attachToClass – > attachCategories
4. There is no load method:
->main (delay until the first message is sent, initialize ->data())
5. There are many categories, but not all of them have load methods:
Methods: write a classification for the main class, write object method class method in the classification, break point trace print method whether there is a classification method.
The flow chart
Problem complement
Do the sorted loads need to be sorted?
Don’t need. Reference before the analysis of the classification of the load is divided into four kinds of circumstances, and altogether after three scenarios are read by ro, when ro read, also is the system to determine, in binary search, to iterate over, that is, “-” to find the classification of the previous methods, this method is to save the list of all the classification methods, also have no order, And it’s a one-dimensional array, so it can be “–“, but in the first case where the main class has loads, then attachCategories, which has already been inserted into the method, is just the first of the categories.
Supplementary control over the order in which compilation classes are compiled
When you write several categories for a main class, and all implement the same method of the category, since the categories are unordered, which method of the category depends on the compilation order, how the compilation order came from? It was decided when you first created it. If you want to change it, you can adjust the order by compile Sources in the buildPhases, and the lower the order, the higher the order.
Why is it possible to read ro data through address type force-feed?
Because during the LLVM compiler compilation phase, the compiler has already assigned values for us according to the address.
Method_list_t data structure?
We’re going to store an array of pointer types, and we’re going to get the address of the pointer to method_t, and method_t is where we’re going to store methods and all the data associated with them.
The main class has no load, and the classification has special cases of the load method
If there is only one category, then according to the previous analysis, it will not take attachCategories, but if there are multiple categories and at least two of them implement load, it will also take attachCategories, which is odd, if the main class does not implement load. In break point debugging, both the main class and the category implement the load method, so it’s going to go through loadAllCategories, and if the main class doesn’t implement load and only one of the categories implements load, it’s going to go through nothing, and if there are two categories implemented, it’s going to go through prepare_load_methods, Then, the realizeClassWithoutSwift will force the main class to open. In this case, just like our first case, attachCategories will be used. In addition, if a new category is created and nothing is done, the total number of categories is not counted. In cats_count, only categories that already have an implementation method are counted (even if there is no load method).
Afterword.
As long as one side writes the load method, it will go through the process of non-lazy loading. It will write more methods, and go more! If not, then these methods will be put directly into the data by the system via Macho the first time the message is sent, so we don’t need to add the load method unless it is necessary!
Write so much for the time being ~~ later to add ~ make up a lesson too heart tired, finally round back behind understand.