In the previous article OC Underlying Principles 11: Class Loading (part 1), we understood how classes are loaded into memory from Mach-O. This time we will explain how classes are loaded into classes and how they are used together.

Nature of classification

The premiseIn:mainDefined in theLGPersontheClassification of LG There are three ways to explore the nature of classification:

  • [Method 1] Throughclang
  • [Method 2] PassXcodeDocument searchCategory
  • [Method 3] PassobjcThe source code searchcategory_t

[Method 1] Throughclang

Clang-rewrite-objc main.m -o main.cpp looks at the underlying compilation, main.cpp

  • Among themclassificationIs of type_category_t There are two method_list_t, respectivelyInstance methods 和 Class method
  • LGclassificationThe penultimate 0 of the category is zeroNo agreement, soThe assignment is 0
  • search_CATEGORY_INSTANCE_METHODS_LGPerson_, find its underlying implementation:There are three methods in the format:Sel + signature + address, it ismethod_tThe attributes of the structure are called keys
    • searchmethod_t, the corresponding relationship is as follows
      • nameThe correspondingsel
      • typeThe correspondingThe method signature
      • impThe correspondingFunction addresses

In the meantime, we found oneThe problem: check it_prop_list_tMing MingclassificationDefined in theattribute, but the properties are not seen in the underlying compilation, as shown in the figure below, becauseProperties defined in a class do not generate method implementations and underlined member variables, only setter and getter method declarations for variablesWe can go throughassociationsTo set (how to setassociationsIn the next oneIllustrate)

[Method 2] Search for categories through Xcode documents

throughXcodeDocument searchCategory

[Method 3] Search for category_t from objC source code

conclusion

In summary, classification is essentially a CATEGORY_T type

  • There are two properties:Name (class name)CLS (Class object)
  • There are twomethod_list_tA list of methods of type that represent those implemented in the classificationInstance method + class method
  • aprotocol_list_tType, representing the protocols implemented in the classification
  • aprop_list_tAttribute list of type, representing the attributes defined in the classification. Generally, the attributes added in the classification are passedassociationsTo implement the
  • It is important to note that in the classificationattributeThere is noThe set and getmethods

Classification loading

Premise: Create two categories for LGPerson: LGA and LGBIn the lastIOS – Basic Principles 17: Loading classes (part 1)In the articlerealizeClassWithoutSwift -> methodizeClass -> attachToClass -> load_categories_nolock -> extAlloc ->attachCategoriesThe rWE loading is mentioned, which analyzes the classification ofdataHow is the data loaded intoclass, and the loading sequence of the classification is:LGA -> LGBThe sequence loaded into the class, i.eThe later you add it, the more advanced it is.

One viewmethodizeClassThe source code implementation can be foundClass of dataandClassified dataIt’s handled separately, mainly because inCompilation phase, has been determinedThe home location of the method(i.e.Instance methodsStored in theclass,Class methodStored in theThe metaclass), and theclassificationIt was added later.

Classification loading is mainly divided into three steps:

  • 1 Disaggregated data of 1 ️Loading time: according to theWhether classes and classes implement load methodsTo distinguish between different times
  • 2 ⃣ ️attachCategoriesTo prepareCategorical data
  • 3 ⃣ ️attachListswillClassification data is added to the main classIn the

From the previous iOS- Basic Principles: Class loading (1) we have already known the last two steps of the three steps of classification loading, the next step to discuss the classification loading time.

The loading time of the classification

Case 1: Take the main LGPerson + LGA and LGB +load method as an example.

Data preparation (based on step 2 2 retail ️attachCategoriesTo prepareCategorical data) reverse the loading time of the first step

From the previous article, we learned that when we go to attachCategories method, categorization data must be loaded. We can check when to call attachCategories by backward method. By searching, we can call them in two methods:

  • load_categories_nolockIn the method

  • attachToClassMethod, as you can see from debugging here, never goes into the if flow unless it’s loaded twice, and a normal class will only load once

  • Running objC code without any breakpoints yields the following printed log, which can be found from the logattachToClassThe next step in the method isload_categories_nolockApproach is toLoading classification Data

  • Global search “load_categories_NOLock” applies. There are two categories_nolock calls:

    • Once inloadAllCategoriesIn the method
    • Once in_read_imagesIn the method

    But after debugging, it will not go_read_imagesMethod of if flow, but walkloadAllCategoriesMethod.

  • Global search viewloadAllCategoriesIs found in theload_imagesWhen the call

Through stack information analysis

inattachCategoriesAdd custom logic breakpoints,btView stack information:

Therefore, in this case, the backward application path of data loading time of the categories is attachCategories -> load_categories_NOLock -> loadAllCategories -> load_images

The normal path of our classification loading process is: realizeClassWithoutSwift -> methodizeClass -> attachToClass ->attachCategories

The forward and reverse processes are shown in the figure below:

Let’s look at another case 2: the main class + classification LGA implements +load, while the classification LGB does not implement +load

  • Breakpoint is set onattachCategoriesAdd custom logic part step by step
  • If you keep going, it will come againattachCategoriesMethod interrupt

Summary: As long as there is a non-lazy load category, then all categories will be marked as bit non-lazy load category, meaning that the rWE has been loaded once, it will not be lazy to load again, to deal with LGPerson again.

Assorting use of categories and classes

Based on the above two cases, we can roughly divide the cases of +load into four categories:

Kind of + classification
Classification implementation +load Classification is not implemented +load
Class implements + load Non-lazy loading class + non-lazy loading class Non-lazy loading class + lazy loading class
Class does not implement +load Lazy loading class + non-lazy loading class Lazy loading class + lazy loading classification
  • [Situation 1]Non-lazy loading class + non-lazy loading class
  • 【 situation 2】Non-lazy loading class + lazy loading class
  • 【 situation 3】Lazy loading class + lazy loading classification
  • 【 situation 4】Lazy loading class + non-lazy loading class

Non-lazy loading class + non-lazy loading class

That is, the main class implements the +load method, and the class implements the +load method. In the loading time of the above classification, we have analyzed this situation, so we can directly draw the conclusion that in this case:

  • Class data is loaded through_getObjc2NonlazyClassListLoad, ro, RW operations, rightrweAssignment is initialized inextAllocIn the method
  • Classified data loadingIs through theload_imagesLoad into a class

Its invocation path is:

  • map_images -> map_images_nolock -> _read_images -> readClass -> _getObjc2NonlazyClassList -> realizeClassWithoutSwift -> methodizeClass -> attachToClassFor the time of,mlistsIt’s a one-dimensional array, and then it goes toload_imagesPart of the
  • load_images --> loadAllCategories -> load_categories_nolock -> load_categories_nolock -> attachCategories -> attachListsFor the time of,mlistsis2 d array

The following is a debug log printed in the source code:

Non-lazy loading classes and lazy loading classification

That is, the main class implements the +load method, but the class does not implement the +load method.

  • Open therealizeClassWithoutSwiftCustom breakpoints in, look at ro
    • To viewkc_ro

    As you can see from the printout above, the order of methods isLGB - the LGA - LGPerson class, the classification has been loaded, but there is no sorting, indicating that when there is no non-lazy loading, passcls->datareadMach-OData is already compiled and does not need to be added at runtime

  • Came tomethodizeClassMethod breakpoint section
  • Came toprepareMethodListsFor loop
  • Came tofixupMethodListIn the methodif (sort) {Part of theAmong themSortBySELAddressThe source code implementation is as follows:Sort by address of name
  • Go to themlist->setFixedUp();, reading the list

Found through printing, onlyThe methods with the same name are sorted, and other methods in the classification is not required to sort, its IMP address is ordered (from small to large) —fixupMethodListThe sortingSort only for the name address

Run the program without any breakpoints to get the print log:

Conclusion: Data loading of non-lazy loading classes and lazy loading classes can be concluded as follows:

  • Loading of classes and categoriesIs in theread_imagesI load the data
  • Among themThe data of datainCompile timeIt’s already done

Lazy loading classes and lazy loading classification

That is, neither the main class nor the classification implements the +load method

  • Run the program without any breakpoints to get the print logAmong themrealizeClassMaybeSwiftMaybeRelockIs a function of slow lookup in the message flow, i.eThe first time a message is invokedIt’s just a function.
  • inreadClassBreak and readkc_roThat is, read the wholedata At this timebaseMethodListthecountIt’s still 16. So is the descriptionRead from dataSo you don’t have to go through a layer of slowload_imagesLoading in

Summary: Lazy loading classes and lazy loading classes load data when the message is first called.

Lazy-loaded classes and non-lazy-loaded classes

That is, the main class does not implement the +load method, the class implements the +load method

  • Run the program without any breakpoints to get the print log
  • It is not found in the printed logload_categories_nolockMethod, viewattachCategories -- extAlloc -- attachToClass -- attachCategoriesIn theattachToClassAdd a breakpoint
  • inreadClassMethod interrupts and viewskc_ro Among thembaseMethodListThe count is8Object method 3 + attribute setget method total 4 +1 CXX method, that is, now only the main class data
  • To debug classified data loading, proceed further,btView the stack:load_images -> loadAllCategories -> load_categories_nolock

Summary: Lazy loading class + non-lazy loading class data loading, as long as the class implements load, will force the main class to load in advance, that is, the main class forced to convert to non-lazy loading class style

conclusion

Class and classification are used together, and the loading time of its data is summarized as follows:

  • [Situation 1]Non-lazy loading class + non-lazy loading classAnd its data is loaded inload_imagesMethod, the class is loaded and classified information is pasted to the class
  • 【 situation 2】Non-lazy loading class + lazy loading class, its data is loaded inread_imageLoad the data. The data comes fromdataThe data inCompile timeThat is, in addition to the data of the class, the data of the classification is bound to the class
  • 【 situation 3】Lazy loading class + lazy loading classificationAnd its data loadingDefer until first message, data also come fromdataThe data inCompile timeIt’s already done
  • 【 situation 4】Lazy loading class + non-lazy loading classAs long as the class implements load, it forces the main classLoading in advanceIn which the_read_imagesDoes not implement classes inload_imagesMethod that triggers the data loading of the class, i.eRwe initializationAnd load classified data at the same time

As shown below:

Addendum: Load_images principle analysis

The load_images method is mainly used to load image files. The two most important methods are prepare_load_methods (discovery) and call_load_methods (call).

  • Enter theload_imagesThe source code to achieve

Enter theprepare_load_methodsThe source code

– to enter_getObjc2NonlazyClassList -> schedule_class_loadSource code, here is mainly based onClass's inheritance chain recursively calls to get the loadTo stop recursion until CLS does not existTo ensure that the parent class loads first – to enteradd_class_to_loadable_list, mainly willLoad method and CLS class nameTogether to theloadable_classesIn the table– to entergetLoadMethod, mainly to obtain methodsSel for the loadThe method of

  • _getObjc2NonlazyCategoryList -> realizeClassWithoutSwift -> add_category_to_loadable_list, the load method of non-lazy load classification is added to the table
    • Enter theadd_category_to_loadable_listImplementation, get all the load methods in the non-lazy load classification, willClassification of + loadJoin tableloadable_categories

Enter thecall_load_methodsSource code, the main3Part of the operation

  • Repeated callsClass + loadUntil there are no more
  • Call the +load of the class once
  • If there are classes or more untried classifications, run more+load

  • Enter thecall_class_loads, mainlyThe load method that loads the class Among themloadThe method has two hidden arguments, the first of which isId is the self, the second isSel, namely the CMD

  • call_category_loads, mainly the load method of loading a classification once

To sum up, the overall calling process and principle of load_images method are shown as follows:

  • Call procedure diagram

  • Principle of graphic

    There are two main steps

    • + loads from all non-lazy-loaded classes and classes are added to the table separately

    • Call the +load method for classes and categories

reference

This article learns and references iOS- Underlying Principle 18: Class loading (2), thanks here

The article lists

List of blog posts