This is the fourth day of my participation in the August More text Challenge. For details, see: August More Text Challenge
Member variables & attributes & instance variables
-
Property: in OC, a property is defined beginning with @property and is a variable with an underscore member variable + setter + getter method
-
Member variable (IVar) : a variable defined in class {} of OC that has a basic data type and is not underlined
-
Instance variable: a special type of variable that is instantiated by the current object type
Member variables, such as NSObject, UILabel, UIButton, or your own class
What are member variables, what are attributes, and what are instance variables in our class?
attribute
: nickName, acnickName, nnickName, anickName, name, aname.Member variables
A. hobby B. hobby C. hobby D. hobbyThe instance variables
: objc.
Let’s clang the main file and explore the underlying structure to see the relationship between properties and member variables.
Open the main.cpp file and find our LGPerson class.
So we see that the properties in the CPP file, the properties are useless. It is optimized as an underlined member variable in CPP and getters and setters are generated automatically.
So let’s notice why some of the set methods use objc_setProperty, some of the methods do assign by a memory shift, some of the methods do get by objc_getProperty, some of the methods do get by a memory shift.
We think that all setters do almost the same job, which is to assign to a memory area. If we wanted a low-level implementation for each setter, it would be too cumbersome, so Apple encapsulated the base class method at the bottom. And then in the middle we create a method called objc_setProperty, and the underlying code implementation of the objc_setProperty, and the setter calls the base class method through the intermediate method, objc_setProperty.
Next we open LLVM and search for objc_setProperty.
So we see there’s a place where we create and return objc_setProperty methods.
After seeing that the name of this method is getSetPropertyFn, which means that this method is going to get the setProperty method, we search LLVM for this method.
It turns out to be a middle tier code, so we’ll search for GetPropertySetFunction instead.
Then we found this function calls, and found that when PropertyImplStrategy SetPropertyAndExpressionGet and GetSetProperty will call this method.
We scroll up and see that we’re trying to determine the type of the instance variable strategy, which is derived from the type of PropertyImplStrategy. So we need to find out where PropertyImplStrategy is being assigned. Therefore, we look for PropertyImplStrategy in LLVM where it was initialized.
We see that this is initialized, and we click on this method.
Here we see that when there is a copy, PropertyImplStrategy will be copied to the GetSetProperty property. So copy is the determinant of whether or not to call objc_setProperty. So let’s verify that.
In the CPP file, it is true that the set_property method is called only after the copy is added, and the rest is assigned by a memory shift.
Class method
LLDM prove
In the iOS Low-level exploration section – Class Principle analysis – above, we found that the class method is not in the class method list, so where is it?
Let’s add a class method say666 to LGPerson. If you put both an object method and a class method in a class, they will not be found if they have the same name. So Apple came up with a way to create a metaclass and store the class methods in the metaclass. To verify:
The runtime prove
-
lgObjc_copyMethodList
Let’s first create a method to print all the methods of the class.
Then pass in the class and the metaclass, and see what we print.
We found that say666 did indeed exist in the metaclass.
-
lgInstanceMethod_classToMetaclass
A class method is an object method to a metaclass, so as you can see, this proves that an object method is inside the class, and a class method is inside the metaclass.
-
lgClassMethod_classToMetaclass
The output here is a little odd. Object methods are not found in classes or metaclasses, and class methods are found in both classes and metaclasses. Let’s take a look at how class_getClassMethod is implemented at the bottom.
As we can see, we’re actually calling the method that gets the object’s method, but we’re dealing with CLS. Let’s look at the getMeta method again.
It turns out that this method will determine whether the class passed in isa metaclass or not, and if it is, it will return itself. If it is not, it will return isa. We know that the class’s isa refers to its metaclass, so return isa is the metaclass of the class. Therefore, methods that print objects with this method are empty, while class methods can print in both classes.
-
lgIMP_classToMetaclass
In this method, we find that the IMP of metaclass object finding method, class finding class method actually has value, and their value is the same. Why is that?
How is it possible to search class_getMethodImplementation in the source code
On the way, we see that the class_getMethodImplementation method returns _objc_msgForward if the IMP is empty, which explains why the two IMPs have a value and are the same value.
Type encoding
In main.cpp, we see some strange symbols:
This is actually TypeEncodings. The purpose of TypeEncodings is to assist the runtime system. The compiler encodes the return value of each method and the parameter types and method selectors as strings. The compiler internally replaces each method’s return value, parameter type, and method selector -> with a specific character. We can find it through a few steps: So we go to Help for XCode, and then we go to Deveoper Documentation, Or open Xcode directly and press Command + Option + 0 to open Developer Documentation, and then search for ivar_getTypeEncoding in Developer Documentation.
Then click on the type Encodings and the system will jump to the official Apple document and we can see the table of the type Encodings.
Now that we know what these are, let’s scroll down. We saw something strange again.
As we can tell from the method names, this is a list of object methods, but what does the red box for “Kiki baby” mean? Those symbols are type codes, so what are numbers? Let me give you 🌰 : let’s take @16@0:8 as an example
@
: Returns @, found in the type encoding table, where @ represents id16
: indicates the total number of bytes. 16 bytes@
: The first argument is @, which is id0
: The first parameter takes 8 bytes starting from 0:
: The second parameter is:, which is found in the type coding table. : represents SEL8
: The second argument takes 8 bytes, starting with 8 bits
Here’s another: 🌰 : v24@0:8@16
V
: returns the value V, found in the type encoding table, where V stands for void24
: indicates the total number of bytes. 24 bytes@
: The first argument is @, which is id0
: The first parameter takes 8 bytes starting from 0:
: The second parameter is:, which is found in the type coding table. : represents SEL8
: The second argument takes 8 bytes, starting with 8 bits-
@
: The third argument is @, which is id
16
: The third parameter takes 8 bytes, starting with 16 bits
Interview question: isKindOfClass/isMemberOfClass
Topic:
Methods:
Analysis:
BOOL re1 = [(id)[NSObject class] isKindOfClass:[NSObject class]];
We’re calling the isKindOfClass class method here, and according to the above method, CLS is class NSObject.
- When I go in the first loop
TCLS is equal to NSObject->ISA(), which is the NSObject metaclass
, sotcls! =cls
. - Then,
The second time
Loop,tcls = tcls->getSuperclass()
, that is,NSObject metaclass
theThe parent class
That isNSObject class
, sotcls == cls
To return totrue
.
BOOL re2 = [(id)[NSObject class] isMemberOfClass:[NSObject class]];
- This is calling the class method isMemberOfClass, and based on the above method,
CLS is NSObject class
.self->ISA()
That’s what ISA for NSObject points toNSObject metaclass
So return self->ISA() == CLSfalse
.
BOOL re3 = [(id)[LGPerson class] isKindOfClass:[LGPerson class]];
- So what I’m calling here is
IsKindOfClass of
Class methods, based on the methods above,CLS is LGPerson class
. - The first
one
The sub loop goes inTCLS is equal to LGPerson->ISA() which is LGPerson metaclass
, sotcls! =cls
. - Then the first
two
Sub-cycle,tcls = tcls->getSuperclass()
, that is,LGPerson metaclass
theThe parent class
That isNSObject metaclass
, soTCLS! = cls
. - Then the first
three
Sub-cycle,tcls = tcls->getSuperclass()
, that is,NSObject metaclass
theThe parent class
That isNSObject class
, soTCLS! = cls
. - The first
four
Sub-cycle,The superclass of class NSObject is null
, so TCLS is null, the loop ends, and returnsfalse
.
BOOL re4 = [(id)[LGPerson class] isMemberOfClass:[LGPerson class]];
- This is calling the class method isMemberOfClass, and based on the above method,
CLS is LGPerson class
.self->ISA()
That’s what THE LGPerson class isa points toLGPerson metaclass
So return self->ISA() == CLSfalse
.
BOOL re5 = [(id)[NSObject alloc] isKindOfClass:[NSObject class]];
- So what I’m calling here is
isKindOfClass
theObject methods
According to the above method,CLS is NSObject class
. - When I go in the first loop
TCLS is equal to self class, the class of NSObject, which is the class of NSObject
, sotcls==cls
To return totrue
.
BOOL re6 = [(id)[NSObject alloc] isMemberOfClass:[NSObject class]];
- So what I’m calling here is
isMemberOfClass
theObject methods
According to the above method,CLS is NSObject class
. The class of an NSObject is class NSObject
So [self class] == CLS,Returns true
BOOL re7 = [(id)[LGPerson alloc] isKindOfClass:[LGPerson class]];
- So what I’m calling here is
isKindOfClass
theObject methods
According to the above method,CLS is LGPerson class
. - When I go in the first loop
TCLS is equal to self class, the class of the LGPerson object is the LGPerson class
, sotcls==cls
To return totrue
.
BOOL re8 = [(id)[LGPerson alloc] isMemberOfClass:[LGPerson class]];
- So what I’m calling here is
isMemberOfClass
theObject methods
According to the above method,CLS is LGPerson class
. The class of the LGPerson object is the LGPerson class
So [self class] == CLS,Returns true
Verify the output:
Pit:
According to the assembly, there’s a pitfall: isKindOfClass actually calls the objc_opt_isKindOfClass method. The implementation is as follows:
You still get the same result.