preface
In the previous chapter, we explored the underlying structure of classes
isa
Points to the graph, and introducesThe metaclass
, includingclass
theisa
Will pointThe metaclass
;- And you know it
class
theInheritance chain
; - And then we explored
class
The underlying structure of theclass
The inside of thebits
Variables do the main exploration (here everyone in the exploration of the time to pay attention to inobjcSource probe), got itbits
It storesattribute
.methods
.agreement
And so on; - It is further found that the member variable does not exist
class_rw_t
thepropertys
In, but inclass_ro_t
theivar_t
; - Object methods exist in classes
class_rw_t
themethods
, class methods have metaclassesclass_rw_t
themethods
In 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_t
Is to belong toClean Memory
Because theclass_ro_t
It’s read-only;Clean Memory
It 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 becomes
Dirty Memory
, because the runtime writes new data to it; For example, create a new method cache and point to it from the class. Dirty Memory
thanClean Memory
It 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 in
runtime
Can be modified when;- when
Category
When loaded, it can add methods to the class; - through
runtime
apiDynamically adding properties and methods;
- when
class_ro_t
It’s read-only. It needs to be inclass_rw_t
Track 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_t
To 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_t
Optimization 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:
nickName
andobjc
Are allMember variables
But we need to be careful hereobjc
Actually, 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), becauseNSObject
Not the base type; The basic data types are all member variables, and the rest are instance variables;name1
.name2
As well asage
That’s the property;saySomething
For object methods,sayHello
As 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 shows5
A, but let’s just say that2
Yeah, and3
What 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 throughclang
Compiled into.cpp
File 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 =
_ properties
Member 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,name2
Is assigned by the first address plus an offset, andname1
Is through aobjc_setProperty
Method, why do different methods appear for the same typeset
Style? Is it because we gave different modifiers?
objc_setProperty
supplement
So we need to understand what objc_setProperty means, right?
LLVM
In 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),atomic
Etc.
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.
objc
In 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 calledreallySetProperty
Method, 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 |
A char |
i |
An int |
s |
A short |
l |
A long``l is treated as a 32-bit quantity on 64-bit programs. |
q |
A long long |
C |
An unsigned char |
I |
An unsigned int |
S |
An unsigned short |
L |
An unsigned long |
Q |
An unsigned long long |
f |
A float |
d |
A double |
B |
A C++ bool or a C99 _Bool |
v |
A 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 |
b num |
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 from16
Position to start@
Parameters:0
: the parameters from0
Position to start:
:SEL
8
:SEL
from8
Position to start