preface

In the previous chapter, we explored the underlying structure of classes

  • isaPoints to the graph, and introducesThe metaclass, includingclasstheisaWill pointThe metaclass;
  • And you know itclasstheInheritance chain;
  • And then we exploredclassThe underlying structure of theclassThe inside of thebitsVariables do the main exploration (here everyone in the exploration of the time to pay attention to inobjcSource probe), got itbitsIt storesattribute.methods.agreementAnd so on;
  • It is further found that the member variable does not existclass_rw_tthepropertysIn, but inclass_ro_ttheivar_t;
  • Object methods exist in classesclass_rw_tthemethods, class methods have metaclassesclass_rw_tthemethodsIn the.

Class_rw_t and class_ro_t are the two brothers of class_rw_t and class_ro_t. We know that the system also generates member variables with _ attribute names for attributes in ivar_t of class_ro_t. What’s the relationship between attributes, member variables, and instance variables? Let’s look at the underlying structure of classes in the next chapter.

Class in Memory

Before we dive into that, let’s take a look at Apple’s WWDC 2020 video on runtime memory optimization;

Through the video, we can see that this time is mainly to optimize the internal data structure to make the App run faster. There are two concepts in this, Clean Memory and Dirty Memory. What are the two? Continue watching the video to find out:

Clean Memory

  • Memory that does not change after loading;
  • class_ro_tIs to belong toClean MemoryBecause theclass_ro_tIt’s read-only;
  • Clean MemoryIt can be removed to save more memory space if you need toClean Memory, the system can reload from disk

Dirty Memory

  • Memory that changes while the process is running;
  • The class structure becomesDirty Memory, because the runtime writes new data to it; For example, create a new method cache and point to it from the class.
  • Dirty MemorythanClean MemoryIt is much more expensive and must exist as long as the process is running.

In macOS, you can swap out the Dirty Memory by using the swap option. In iOS, you don’t use swap, so Dirty Memory is very expensive in iOS. So Dirty Memory is the reason why this class is divided into two parts. Most of the classified data can be stored in Clean Memory by separating the data that never changes.

We know the class is on disk

We need to know more about the class at runtime, so when the class is first loaded into memory, Runtime allocates extra storage for it. The extra storage allocated is for class_rw_t to read and write data. In this data structure we will store only new information that is generated at runtime. For example, all classes will be linked into a tree structure. This is done with First SubClass and Next Sibling Class Pointers, which will allow Runtime to traverse all the classes currently in use. It is useful to invalidate the method cache.

Given the above diagram, we must wonder why methods and attributes in class_ro_t also exist in class_rw_t when they are optimized to save memory space. The video also explained to me:

  • They are inruntimeCan be modified when;
    • whenCategoryWhen loaded, it can add methods to the class;
    • throughruntime apiDynamically adding properties and methods;
  • class_ro_tIt’s read-only. It needs to be inclass_rw_tTrack the data.

We know that there will be a lot of classes in the project, so this will take up a lot of memory, so how do you shrink these structures?

class_rw_tTo optimize the

Runtime can add properties and methods dynamically, but Apple’s actual monitoring shows that only about 10% of classes are dynamically changed. One of the fields, demangledName, is needed only if swift has an objective-C name that needs to be accessed. So you can break down the parts that you don’t normally use:

In this case, the size of class_rw_t is halved; For classes that need to modify memory and need additional information, we can allocate one of these extended records and slide it into the class for its use:

class_rw_tOptimization summary of

The optimization of class_rw_t is essentially to split the infrequently used data within the Class_rw_ext_t extension; If you need to use this data, allocate a slide from the Class_rw_ext_t extension to the class for its use.

Variables, properties, methods in a class

We know that a class usually has variables, properties and methods. Here’s our declared class LhkhPerson that inherits from NSObject:

  • nickNameandobjcAre allMember variablesBut we need to be careful hereobjcActually, we should call it thetaThe instance variables(defined as a member variable other than the underlying data type, so instance variables are a special kind of member variable), becauseNSObjectNot the base type; The basic data types are all member variables, and the rest are instance variables;
  • name1.name2As well asageThat’s the property;
  • saySomethingFor object methods,sayHelloAs a class method

We added in the last section that member variables are stored in ivar_t of class_ro_t,

We find that its member variable shows5A, but let’s just say that2Yeah, and3What is one?

We can find out by taking the data in ivars

These three properties are kind of similar to the properties we defined. Why is there a ‘_‘? And then we go throughclangCompiled into.cppFile to see the underlying code implementation:

At compile time, the system converts the property into a member variable of the _ property and its corresponding getter and setter methods.

So we get:

  • Property =_ propertiesMember variable + getter method + setter method

If we’re careful, we’ll see that name1 and name2, which are both NSString, are different setters

In the figure above we can see that,name2Is assigned by the first address plus an offset, andname1Is through aobjc_setPropertyMethod, why do different methods appear for the same typesetStyle? Is it because we gave different modifiers?

objc_setPropertysupplement

So we need to understand what objc_setProperty means, right?

LLVMIn the sourceobjc_setProperty

Since this occurs at compile time, we need to start with LLVM, using vscode to open LLVM source code:

We found this method by searching for objc_setProperty, create objc_setProperty method at run time, now that we have found the method, let’s go backwards. When does getSetPropertyFn() get called? Keep searching:

GetPropertySetFunction()Method, this is an intermediate method, so keep lookingGetPropertySetFunction()Call:

We see that this is a Switch, and the call to GetPropertySetFunction() is under the PropertyImplStrategy of the Switch, And this will correspond to the two GetSetProperty ` ` and SetPropertyAndExpressionGet, that we now just need to know when the assignment aren’t this strategy with respect to ok, continue to find:

Is it a copy modifier;

There areretain(In MRC mode, most of them are in ARC mode now, so all retain is not needed to understand),atomicEtc.

Let’s take an example to verify:

conclusion

So what we basically have is that in the case of the copy modifier, whether it’s atomic or non-atomic, the setter methods that the system generates are going to redirect to the objc_setProperty method.

objcIn the sourceobjc_setProperty

We saw this method with objc in front of it and we were wondering if there was a way to implement objC in the source code, and we searched and we found out

From the source code we found that there are five methods, and we also found thatatomic.copy.nonatomic; And all five methods are calledreallySetPropertyMethod, in which the essence is new valuesretain, the old valuerelease.

coding

We will see this in the generated CPP file

In this"v16@0:8","@ @ 0:8 16"What do these codes mean… Please see the official code explanation:

The official code

We can search for ivar_getTypeEncoding by going to Xcode –> Command + Shift +0–> search for ivar_getTypeEncoding–> Type Encodings

portal

Code Meaning
c char
i An int
s short
l long``l is treated as a 32-bit quantity on 64-bit programs.
q long long
C An unsigned char
I An unsigned int
S An unsigned short
L An unsigned long
Q An unsigned long long
f float
d double
B A C++ bool or a C99 _Bool
v void
* A character string (char *)
@ An object (whether statically typed or typed id)
# A class object (Class)
: A method selector (SEL)
[array type] An array
{name=type… } A structure
(name=type… ) A union
bnum A bit field of num bits
^type A pointer to type
? An unknown type (among other things, this code is used for function pointers)

It can also be printed in code

Long double is not supported in Objective-C. @encode(long double) returns d, which is the same as the encoding value of double.

Let’s use name1a as an example “@16@0:8”.

  • @: corresponds to the ID type parameterself
  • 16: The upper parameter is from16Position to start
  • @Parameters:
  • 0: the parameters from0Position to start
  • ::SEL
  • 8:SELfrom8Position to start