preface

On an iOS underlying principle that article class loading principle, finally when it comes to readClass function through, still don’t see the ro and related operations of rw, today just readClass function to continue to explore.

The preparatory work

  • Objc4-818.2 – the source code

I. Introduction of realizeClassWithoutSwift

Take a look at the SSLPerson class:

@interface SSLPerson : NSObjec
- (void)say1;
- (void)say2;
- (void)say3;
@end

@implementation SSLPerson
+ (void)load
{
    NSLog(@"load");
}
- (void)say1
{
    NSLog(@"func-----say1");
}
- (void)say2
{
    NSLog(@"func-----say2");
}
- (void)say3
{
    NSLog(@"func-----say3");
}
@end
Copy the code

Now that we have analyzed the _read_images function to execute readClass, let’s go further and add the conditional control code for the SSLPerson class to the source code:

Run the program to see if you can enter the breakpoint:

  • You can see that the breakpoint entered successfullyclsIt’s oursSSLPersonClass. inrealizeClassWithoutSwiftThe break point at the function, and then the break point entersrealizeClassWithoutSwift.

Second, realizeClassWithoutSwift analysis

The ro baseMethods

Breakpoint to enter realizeClassWithoutSwift:

Debug via LLDB print:

  • As you can see by printing,roThe list of methods in this time already has values, respectivelysay4,say1,say2,say3“, so let’s move on.

Rw and RO operations

  • This code, createrwThat will beroThe value is assigned torwAnd thenrwAssigned to the classbitsAnd keep going.

Isa related processing

  • If it isMetaClassTo callsetInstancesRequireRawIsaFunction.
  • notMetaClassIf this parameter is setDisableNonpointerIsaValue of, will also be carried outinstancesRequireRawIsaRelated treatment, last articleUnderlying principles of iOS: class loading principlesWe have toDisableNonpointerIsaThe environment variable has been operated. Procedure

SetSuperclass, initClassIsa

Keep going:

  • This is a recursive settingsuperClassOf the inheritance chain, andisaThe location chain of.

  • If I do a little bit more Settings, I’ll get tomethodizeClassFunction, we’re going to go intomethodizeClassExplore, as shown here2751Line.

Three, methodizeClass analysis

Break point to methodizeClass:

  • Here bybaseMethods()Gets a list of methods, if any, and calls themprepareMethodListsFunctions process methods.

prepareMethodLists

Enter the prepareMethodLists:

static void prepareMethodLists(Class cls, method_list_t **addedLists, int addedCount, bool baseMethods, bool methodsFromBundle, const char *why) { // Add method lists to array. // Reallocate un-fixed method lists. // The new methods are PREPENDED to the method list array. for (int i = 0; i < addedCount; i++) { method_list_t *mlist = addedLists[i]; ASSERT(mlist); // Fixup selectors if necessary if (! mlist->isFixedUp()) { fixupMethodList(mlist, methodsFromBundle, true/*sort*/); }}}Copy the code

fixupMethodList

Click to go to fixupMethodList:

static void 
fixupMethodList(method_list_t *mlist, bool bundleCopy, bool sort)
{
    ...
    // Sort by selector address.
    // Don't try to sort small lists, as they're immutable.
    // Don't try to sort big lists of nonstandard size, as stable_sort
    // won't copy the entries properly.
    if (sort && !mlist->isSmallList() && mlist->entsize() == method_t::bigSize) {
        method_t::SortBySELAddress sorter;
        std::stable_sort(&mlist->begin()->big(), &mlist->end()->big(), sorter);
    }
    ...
}
Copy the code
  • Look at the code,SortBySELAddressIs in accordance with theSELAddress sort. We are inOC Principle Exploration: a slow lookup process for methodsIn the saidSlow search processIn theBinary searchI’m using this sorted list right here, and I’m going to verify it.

Add code before and after the sort code to print the method name and address:

To view the print:

  • The method print order before sorting issay4,say1,say2,say3.
  • After sorting the method print order issay1,say4,say2,say3, the address size is0x100003f81 < 0x100003f8b < 0x100003f90 < 0x100003f95Yes, it is in order from smallest to largest.

Lazy-loaded and non-lazy-loaded classes

To summarize the above flow: Read_images -> realizeClassWithoutSwift -> methodizeClass -> prepareMethodLists -> fixupMethodList.

Non-lazily loaded classes

Going back to the first part of the article, the _read_images function executes readClass, which is the following code:

  • We will beSSLPersonIn the classloadMethod, run the program again, found here the breakpoint can not enter.
  • That’s where it comes inLazy loading classwithNon-lazily loaded classes, if you have+ loadMethod will do a non-lazy load, which will happen when the program startsro,rw,The sortingAnd so on a series of operations, very time-consuming.

Lazy loading class

Non-lazy loading of classes is very inefficient. If all classes are non-lazy loading, it will be very, very time-consuming. Therefore, Apple adopts on-demand loading, that is, lazy loading of classes and loading them when they are needed.

When is the non-lazily loaded class loaded? Through the above process, we can know that the class loading will do RW, RO, sort and other operations, namely realizeClassWithoutSwift, so I will explore this as the entry point.

Add a method call to the SSLPerson class in main.m:

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        SSLPerson *person = [SSLPerson alloc];
    }   
    return 0;
}
Copy the code

Add a breakpoint to the SSLPerson class in realizeClassWithoutSwift and run the program:

  • I can successfully break it here, and thenbtPrint the stack.

  • To see thelookUpImpOrForwardFunction, which we are familiar with, is called during a slow lookup process, that is, when the class is first usedLazy loading class.

The next article will be the exploration of classification loading, there are questions can be more communication in the comment area, click a like to support it!! πŸ˜„ πŸ˜„ πŸ˜„