preface
The sun is shining, the weather is cool, don’t go out for a wave, in this kind of research, I degenerate ah. Anyway, the association between ISA and classes was discovered earlier while exploring objects. So let’s explore classes today, and see what’s so amazing about classes.
The preparatory work
Memory migration
In the previous blog, the nature of objects in IOS Underlying Principles &isa Association class explored the underlying implementation of the first address + offset value of the object if you want to get variables in the memory of the object. Let’s explore memory offsets
Ordinary pointer
int main(int argc, char * argv[]) {
@autoreleasepool {
int a = 10;
int b = 10;
int * p = &a;
int * q = &b;
NSLog(@"---%d----%p---%p",a,p,&p);
NSLog(@"---%d----%p---%p",b,q,&q);
}
return 0;
}
Copy the code
2021-06-17 15:07:03.252239+0800 Memory offset [11954:347138] --10---- 0x7ffedFe69C8c -- 0x7FFedFe69C80 2021-06-17 15:07:03.252592+0800 Memory offset [11954:347138] --10---- 0x7ffedFe69c88 -- 0x7ffedFe69C78Copy the code
a
andb
The values are10
, buta
andb
That’s what they sayDeep copy
a
The address is0x7ffedfe69c8c
.b
The address is0x7ffedfe69c88
, the difference between4
Bytes, depending ona
The type ofa
>b
>p
>q
And all of them are inThe stack area
.
The illustration below
Pointer to the object
int main(int argc, char * argv[]) {
@autoreleasepool {
LWPerson * p1 = [LWPerson alloc];
LWPerson * p2 = [LWPerson alloc];
NSLog(@"---%@----%p",p1,&p1);
NSLog(@"---%@----%p",p2,&p2);
}
return 0;
}
Copy the code
2021-06-17 16:00:37.697384+0800 memory offset [12536:388334] --<LWPerson: 0x600002000000>----0x7ffee357bc70 2021-06-17 16:00:37.697465+0800 Memory offset [12536:388334] --<LWPerson: 0x600002000010>----0x7ffee357bc68Copy the code
alloc
Open up internal existenceThe heap area
.A local variable
Open up internal existenceThe stack area
- The heap area
low
Address — — >high
Address, stack areahigh
Address — — >low
address
The illustration below
Pointer to an array
Int main(int argc, char * argv[]) {@autoreleasepool {int c[4] = {1,2,3,4}; int *d = c; NSLog(@"%p - %p - %p ",&c,&c[0],&c[1]); NSLog(@"%p - %p - %p ",d,d+1,d+2); for (int i = 0; i<4; Int value = *(d+ I); int value = *(d+ I); NSLog(@"value = %d",value); } } return }Copy the code
2021-06-17 16:32:13.132035+0800 Memory offset [1299:415236] 0x7ffEEBfd9C80-0x7FfEEBfD9C80-0x7FfEEBfD9c84 2021-06-17 16:32:13.132122+0800 Memory offset [12919:415236] 0x7FfEEBfd9C80-0x7FfEEBfD9C84-0x7FfEEBfD9c88 2021-06-17 16:32:13.132206+0800 Memory offset [12919:415236] value = 1 2021-06-17 16:32:13.132287+0800 Memory offset [12919:415236] value = 2 2021-06-17 16:32:13.132341+0800 MEMORY offset [12919:415236] value = 3 2021-06-17 16:32:13.132418+0800 memory offset [12919:415236] value = 4Copy the code
- The address of an array is the element in the array
The first address
, i.e.,&c
and&c[0]
Are allThe first address
- Between each element of an array
Address space
Based on the current elementThe data type
Decision of the - The addresses of the elements of the array can be passed
The first address
+n
*The type size
In which the elements in the array must be of the same type. - Array elements are different
The first address
+The offset
Method, based on the offset value of the current variable (requires the addition of the previous type sizes)
The illustration below
conclusion
- A memory address is a memory element
The first address
- Memory offset can be based on
The first address
+Offset value
Method to get the address of the relative variable
Class analysis (isa
)
When exploring the object, it is found that the OBJECT’s ISA points to the class. Everything is an object, a class is an object, and there is an ISA in a class. What class does isa refer to? This class is a metaclass defined by Apple.
The metaclass
Metaclasses are automatically generated by the compiler. Why would Apple automatically generate such a class? So let’s explore
Memory number of class objects
int main(int argc, char * argv[]) {
@autoreleasepool {
Class class1 = [LWPerson class];
Class class2 = [LWPerson alloc].class;
Class class3 = object_getClass([LWPerson alloc]);
Class class4 = [LWPerson alloc].class;
NSLog(@"\n-%p-\n-%p-\n-%p-\n-%p-",class1,class2,class3,class4);
}
return
}
Copy the code
-0x100009510-
-0x100009510-
-0x100009510-
-0x100009510-
Copy the code
Source code analysis: class object address is the same, each class in memory only a piece of memory, and ordinary objects have obvious differences
The metaclass inquiry
The LWPerson class has two different addresses, but a class object has only one address. 0x0000000100009500 is the class address of LWPerson, so 0x00000001000094d8 is the class address that Apple calls metaclass
conclusion
The metaclass
It is automatically created by the system compiler and has nothing to do with the user- The object’s
isa
Point to theclass
, class objectisa
Point to theThe metaclass
- Of the class
The name of the class
The class associated with it isThe metaclass
theThe name of the class
Is the same (only the associated metaclass has a class name)
Isa bitmap
object
.class
.The metaclass
There areisa
, and the specificisa
How to go about the process. Create an objectNSObject * obj = [NSObject alloc]
And combined with thelldb
Explore the
NSObject
The object ofobj
theisa
–>NSObject
classNSObject
Of the classisa
–>A metaclass
A metaclass
theisa
–>A metaclass
(To himself)
Customize the LWPerson class, create an object LWPerson * person = [LWPerson alloc], and explore with LLDB
The metaclass isa points to the root metaclass, and the question is: why not NSbOject? Notice that the NSbOject class address is not the same as the root metaclass address, so it points to the root class
LWPerson
The object ofperson
theisa
–>LWPerson
classLWPerson
Of the classisa
–>LWPerson
Of the classThe metaclass
- The metaclass
isa
–>A metaclass
isa
Position flow chart
conclusion
- The object’s
isa
Point to theClass object
- Class object
isa
Point to theThe metaclass
- The metaclass
isa
Point to theA metaclass
- A metaclass
isa
Point to theA metaclass
(To himself)
Inheritance diagram of class, metaclass, root metaclass
First create a LWTeacher class to inherit from LWPerson and explore the inheritance relationship between them. The following code
int main(int argc, char * argv[]) { @autoreleasepool { Class tMetaClass = object_getClass(LWTeacher.class); Class tMetaSuperClass = class_getSuperclass(tMetaClass); Class pMetaClass = object_getClass(lwPerson.class); Class pMeatSuperClass = class_getSuperclass(pMetaClass); Class pMeatSuperClass = class_getSuperclass(pMetaClass); Class nMetaClass = object_getClass(nsobject.class); Class nSuperClass = class_getSuperclass(nsobject.class); Class nMetaSuperClass = class_getSuperclass(nMetaClass); //NSObject Class nMetaSuperClass = class_getSuperclass(nMetaClass); NSLog(@"LWTeacher-%p", lwteacher.class); // NSLog(@"LWTeacher-%p", lwteacher.class); NSLog(@"LWPerson-%p",LWPerson.class); NSLog(@"NSObject-%p",NSObject.class); NSLog(@"%@ - %p - %@ - %p",tMetaClass,tMetaClass,tMetaSuperClass,tMetaSuperClass); NSLog(@"%@ - %p - %@ - %p",pMetaClass,pMetaClass,pMeatSuperClass,pMeatSuperClass); NSLog(@"%@ - %p - %@ - %p",nMetaClass,nMetaClass,nMetaSuperClass,nMetaSuperClass); } return }Copy the code
2021-06-17 22:12:45.737286+0800 testClass[15587:581908] LwTeacher-0x100009618 2021-06-17 22:12:45.737359+0800 TestClass [15587:581908] LWPerson-0x100009528 2021-06-17 22:12:45.737396+0800 testClass[15587:581908] NSObject- 0x7ffF8deb3118 2021-06-17 22:12:45.737434+0800 testClass[15587:581908] LWTeacher - 0x1000095f0 - LWPerson - 0x100009500 2021-06-17 22:12:45.737497+0800 testClass[15587:581908] LWPerson - 0x100009500-nsobject - 0x7ffF8deb30F0 2021-06-17 22:12:44.737540 +0800 testClass[15587:581908] NSObject - 0x7FFF8DEB30f0-nSObject - 0x7FFF8DEB3118 2021-06-17 22:12:45.737583+0800 testClass[15587:581908] - - (null)Copy the code
Source code analysis of NSObject’s superclass prints nil. The parent class of the metaclass of LWTeacher is the metaclass of LWPerson (the address of the metaclass of LWPerson is different from the address of the class of LWPerson). The metaclass of LWPerson is the metaclass of NSObject, and the metaclass of NSObject is the metaclass of NSObject (same address as NSObject)
LWTeacher
inheritanceLWPerson
.LWPerson
inheritanceNSObject
.NSObject
Is the parent classnil
LWTeacher
Yuan class inheritanceLWPerson
Metaclasses,LWPerson
inheritanceA metaclass
.A metaclass
inheritanceNSObject
Flow diagrams of inheritance between classes
Isa bitmap and inheritance map
Apple officially provides the ISA bitmap and inheritance map
Class structure analysis
When exploring the object nature of the underlying principles of IOS & ISA association Class, isa is found to be of type Class. The Class type is objc_class *, and objc_class is a structure. All the underlying implementations of classes are objC_class. Search globally for objc_class in objC4-818.2 as follows
struct objc_class { Class _Nonnull isa OBJC_ISA_AVAILABILITY; #if ! __OBJC2__ Class _Nullable super_class OBJC2_UNAVAILABLE; const char * _Nonnull name OBJC2_UNAVAILABLE; long version OBJC2_UNAVAILABLE; long info OBJC2_UNAVAILABLE; long instance_size OBJC2_UNAVAILABLE; struct objc_ivar_list * _Nullable ivars OBJC2_UNAVAILABLE; struct objc_method_list * _Nullable * _Nullable methodLists OBJC2_UNAVAILABLE; struct objc_cache * _Nonnull cache OBJC2_UNAVAILABLE; struct objc_protocol_list * _Nullable protocols OBJC2_UNAVAILABLE; #endif } OBJC2_UNAVAILABLE; // OBJC2 is not availableCopy the code
Now, normal is OBJC2, and objc_class defined above is not available in OBJC2
struct objc_class : objc_object { ... // Class ISA; Class superclass; cache_t cache; // formerly cache pointer and vtable class_data_bits_t bits; // class_rw_t * plus custom rr/alloc flagsCopy the code
Objc_class inherits objC_object, objc_object has only one member variable isa, isa is specific function has been explored. How to explore the following three member variables whose specific functions are unknown? The address of the class is known, so get the address of the member variable in the class based on the first address + offset value explored above, and then get the value. But the offset value needs to know the size of all member variables before the current variable
isa
Structure pointer occupied8 bytes
Class superclass
It’s also a pointer to a structure8 bytes
cache_t cache
Is the size of the structure type, determined by the member variables in the structureclass_data_bits_t bits
If you know the size of the first three member variables, you can getbits
The address of the
All of objc_class’s member variables can be mapped to their addresses as long as they know the cache_t memory size. Let’s explore the cache_t memory size
typedef unsigned long uintptr_t; #if __LP64__ typedef uint32_t mask_t; // x86_64 & arm64 asm are less efficient with 16-bits #else typedef uint16_t mask_t; #endif struct cache_t { private: explicit_atomic<uintptr_t> _bucketsAndMaybeMask; // 8 union { struct { explicit_atomic<mask_t> _maybeMask; // 4 #if __LP64__ uint16_t _flags; // 2 #endif uint16_t _occupied; / / 2}; explicit_atomic<preopt_cache_t *> _originalPreoptCache; / / 8}; // Here are some methods omitted};Copy the code
Cache_t is a struct type with two member variables, _bucketsAndMaybeMask, and a union
-
The _bucketsAndMaybeMask is uintPtr_t unmarked long integer which takes up 8 bytes
-
There are two member variable structures and _originalPreoptCache in the union. The size of the union is determined by the maximum variable type in the member variable
-
The _originalPreoptCache is an 8-byte structure pointer
-
We have _maybeMask, _flags, _occupied. The maybemask is uint32_t 4 bytes, the flags and the occupied are 2 bytes each and the structure size is 8 bytes
-
Cache_t has a memory size of 8+8 or 8+4+2+2 which is 16 bytes
Explore each member variable in the class. The memory address of the member variable is as follows
isa
Is the memory address ofThe first address
“Has been explored in previous blogssuperclass
Is the memory address ofThe first address
+0x8
cache
Is the memory address ofThe first address
+0x10
bits
Is the memory address ofThe first address
+0x20
Today we will explore the member variable bits and what important information is stored in bits
Bits.data () should store data. The type of data() is class_rw_t*
Class_rw_t is a struct type that provides a method to get a list of attributes, a list of methods, and a list of protocols. To verify that methods, properties, and variables are in class_rw_t, add properties, methods, and member variables to the LWPerson class
Attribute to explore
P $7. Get (index) gets the corresponding property, which is stored in preperty_list_t
p $7.get(2)
Error array out of bounds, property list only2
Attributes, but declared variablesheight
Where is it stored?
At the end of the paper, the variable exploration module under the module is supplemented, and the storage of variables has been explored
Methods to explore
Object methods
Stored in theLWPerson
Classmethod_list_t
In theClass method
Not in theLWPerson
Method listmethod_list_t
In,Class method
Where should I put it?p $7.get(index)
You can’t get a specific value in the method list becausemethod_t
Is processed throughbit()
Get variables
At the end of the article, the class method exploration module is added under the module, and the storage of the class method has been explored
conclusion
There are isa, superclass, CHche and BITS member variables in the class. In the process of exploring bits, we find that bits stores the familiar attribute list, method list, member variable list, protocol list, etc., which opens our understanding of the class. We will continue to explore the class later.
supplement
Variable to explore
There is no variable stored in the class attribute list. Variables are user-defined in the class and should not be placed in the metaclass. Observe that class_rw_t also has a method to obtain class_ro_t *
struct class_ro_t { uint32_t flags; uint32_t instanceStart; uint32_t instanceSize; #ifdef __LP64__ uint32_t reserved; #endif union { const uint8_t * ivarLayout; Class nonMetaclass; }; explicit_atomic<const char *> name; void *baseMethodList; protocol_list_t * baseProtocols; const ivar_list_t * ivars; Const uint8_t * weakIvarLayout; // Uint8_t * weakIvarLayout; property_list_t *baseProperties; // This field exists only when RO_HAS_SWIFT_INITIALIZER is set. _objc_swiftMetadataInitializer __ptrauth_objc_method_list_imp _swiftMetadataInitializer_NEVER_USE[0]; };Copy the code
Class_ro_t is a struct type with an ivar_list_t * ivars variable. Is a list of variables that logically should be stored.
variable
The underlying implementation of isivar_t
. Stored in theclass_ro_t
In the variable list- The system will give
attribute
Automatically generates a tape_ the property name
Variable, stored inclass_ro_t
In the variable list
Class method exploration
Methods of an object are stored in a class, so class methods might be stored in a metaclass. Follow this line of thinking
Class methods are stored in a list of methods in the metaclass