Read_images -> readClass -> realizeClassWithoutSwift(ro.rw.supcls.isa)-> methodizeClass -> realizeClassWithoutSwift(ro.rw.supcls.isa)-> methodizeClass -> PrepareMethodLists (Write the method name in the class. Sort)
read_images
As we know from the readClass test code in the previous article,mangleName can get the name of the class, so we can plug in the read_images test code in several places to verify each one.
const char *mangledName = cls->nonlazyMangledName(a);// Test the code
const char *PersonName = "Person";
if (strcmp(mangledName, PersonName) == 0) {
printf("%s - %s\n",__func__,mangledName);
}
Copy the code
Let’s add the above code validation in log9 and log10 respectivelyThe two breakpoints are not stuck. Look at the note above yellow box 1Realize non-lazy classes (for +load methods and static instances)
Meaning, there areload
This is where they would have gone. So at this point we implement it in the Person classload()
Method, and then run it again. Step over to therealizeClassWithoutSwift
This method
realizeClassWithoutSwift
Does this look familiar? Yes, we’ve been here before when we were exploring the slow search of methods, method linkslookUpImpOrForward
-> realizeAndInitializeIfNeeded_locked
-> initializeAndLeaveLocked
-> realizeClassMaybeSwiftAndLeaveLocked
-> realizeClassMaybeSwiftMaybeRelock
-> realizeClassWithoutSwift
So anyway, let’s go ahead and find out if we implemented methodList ro rw rwe in this methodSo we can get, we just have the address of the Person, but we don’t have any assignment in the method list, ro, rw, rwe, etc.,
auto ro = (const class_ro_t *)cls->data(a);Copy the code
CLS ->data() is of type class_rw_t*, which is strongly converted to class_ro_t *
// Normal class. Allocate writeable class data. ro -> rw
rw = objc::zalloc<class_rw_t> (); rw->set_ro(ro);
rw->flags = RW_REALIZED|RW_REALIZING|isMeta;
cls->setData(rw);
Copy the code
And then it goes over here, where it assigns ro clean memory to RW. The following two lines of code also map the isa inheritance chain and superCls
supercls = realizeClassWithoutSwift(remapClass(cls->getSuperclass()), nil);
metacls = realizeClassWithoutSwift(remapClass(cls->ISA()), nil);
Copy the code
methodizeClass
realizeClassWithoutSwift
-> methodizeClass
Insert the same debug code in this method to intercept the Person information. Continue printing ro as described abovebaseMethodList
Or is emptyMoving on, we find that the system is also calledbaseMethods()
prepareMethodLists
Go to prepareMethodLists and fix the selector fixupMethodList
for (auto& meth : *mlist) {
const char *name = sel_cname(meth.name());
printf("Before sorting: %s - %p\n",name, meth.name());
meth.setName(sel_registerNameNoLock(name, bundleCopy));
}
Copy the code
Now the sort here also corresponds to the slow search binary search. So after I’ve sorted it, I go back to the originalmethodizeClass
So let’s go ahead and do a little bit of ro and find out that there’s still no content and all of that exploration was done in the Person classload
Under the premise that then not implementedload
So where is our method ro, rw assigned
Lazy load class condition (not implementedload
Methods)
Let’s take the Personload
Method, and we know that we’re going to do this methodrealizeClassWithoutSwift
We’re going to cut a break point here and go backwards inrealizeClassWithoutSwift
Breakpoint view call stackAt this point we can draw a conclusion
Lazy load class case: data loading is delayed until the first message | Non-lazy class loading: all class information is recorded when map_images is used |
---|---|
lookUpImpOrForward |
readClass |
realizeClassMaybeSwiftMaybeRelock |
_getObjc2NonlazyClassList |
realizeClassWithoutSwift |
realizeClassWithoutSwift |
methodizeClass |
methodizeClass |
MethodizeClass looks at comments related to categorization, so add a categorization to main and look at main.cpp
struct _category_t {
const char *name; / / class name
struct _class_t *cls; / / class
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
Instance_methods: The class has no metaclass, so all current methods are in there.
static struct/ * _method_list_t* / {
unsigned int entsize; // sizeof(struct _objc_method)
unsigned int method_count;
struct _objc_method method_list[2].
} _OBJC_$_CATEGORY_INSTANCE_METHODS_Person_$_LG __attribute__ ((used, section ("__DATA,__objc_const"))) = {
sizeof(_objc_method),
2,
{{(struct objc_selector *)"cate_instanceMethod1"."v16@0:8", (void *)_I_Person_LG_cate_instanceMethod1},
{(struct objc_selector *)"cate_instanceMethod2"."v16@0:8", (void *)_I_Person_LG_cate_instanceMethod2}}
};
Copy the code
Notice also that the set and GET methods are not included in the list of methods in the category
When is RWE assigned
Going back to the methodizeClass method, we know that the method of classification exists in RWE,
auto rwe = rw->ext(a)Copy the code
Ext () is related to get_ro_or_rwe(), while get_ro_or_rwe() is related to extAllocIfNeeded()
class_rw_ext_t *ext(a) const {
return get_ro_or_rwe().dyn_cast<class_rw_ext_t *>(&ro_or_rw_ext);
}
class_rw_ext_t *extAllocIfNeeded(a) {
auto v = get_ro_or_rwe(a);if (fastpath(v.is<class_rw_ext_t* > ())) {return v.get<class_rw_ext_t *>(&ro_or_rw_ext);
} else {
return extAlloc(v.get<const class_ro_t*>(&ro_or_rw_ext)); }}Copy the code
The global search for extAllocIfNeeded locates this method attachCategories Look at the comment attaching the list of methods, properties, and protocols in the Categories category to the class to show that we are looking right
attachCategories
Found to call the method 1. There are two realizeClassWithoutSwift – > methodizeClass – > attachToClass – > 2 attachCategories load_categories_nolock ->attachCategories -> extAllocIfNeeded In attachCategories we found an algorithm for inserting categories attachLists where the calculation is to insert the categories in front of the ordered list, followed by the methods of the main class. This also explains why when a method with the same name is called, the method lookup will first locate the method with the same name of the class.
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
We know that the loading of a class is related to load, so is the loading of a class related to load
Category + class collocation loading
List all four scenarios below
The classification load method is implemented | Main class load method implementation | Load order |
---|---|---|
There are | There are | _read_images ->realizeClassWithoutSwift ->methodizeClass ->load_categories_nolock ->attachCategories |
There is no | There are | _read_images ->realizeClassWithoutSwift ->methodizeClass (noattachCategories ) |
There are (1) | There is no | _read_images ->realizeClassWithoutSwift ->methodizeClass (noattachCategories ) |
There are (> 1) | There is no | load_images -> prepare_load_methods -> realizeClassWithoutSwift -> methodizeClass -> attachCategories |
There is no | There is no | Nothing |
According to the above four cases, we analyze when the data of the classification is loaded in. At the same time, if the classification has no content, it will not be loaded into memory.
Timing of classification data loading
- In both cases: in
**realizeClassWithoutSwift**
Method console print
Print one by one and find that there are no classified methods, all methods of the main class. We know we’re coming**attachCategories**
, where the print validation continuesIt is found that the classification method has been added here. Moving on, we see the classification insertion algorithm written aboveattachList
rwe->methods.attachLists(mlists + ATTACH_BUFSIZ - mcount, mcount);
Copy the code
We know from the above that the first argument is a pointer to a pointer, which is a two-dimensional pointer
- There is no
**attachCategories**
How to load categories
Whether it’s the class or the main class there’s only one place to implement the load method, or it’s in theread_images
The non-lazy load inside, describes the main class in some cases the classification is forced to business. Now we come to**realizeClassWithoutSwift**
If count=13, the class has already been loaded into the main class. Count is the number of classes read directly from Mach-o.**_read_images**
->**realizeClassWithoutSwift**
->**methodizeClass**
–load_images
->loadAllCategories
-> load_categories_nolock
-> attachCategories
-
It’s the same thing as 2
-
Main class implementation, in the case of multiple categories (more than 1 implementation load), the process is found to be a little different
_read_images
->realizeClassWithoutSwift
-> methodizeClass
-> load_images
-> prepare_load_methods
-> realizeClassWithoutSwift
-> methodizeClass
-> attachCategorie
- In the absence of either implementation, the loading of the classification is delayed until the first message is sent
lookUpImpOrForward
Initialize data when the