Objc_object vs. objc_class
objc_object
The correspondingobject
, it isobject
At the bottomThe data structure
.objc_class
The correspondingclass
, it isclass
At the bottom of theThe data structure
id
forObjc_object pointer
theThe alias
typedef struct objc_object *id; `Copy the code
class
forObjc_class pointer
theThe alias
typedef struct objc_class *Class;
Copy the code
objc_class
Inheritance inobjc_object
Everything is an object
struct objc_class : objc_object {
Copy the code
isa
Source code analysis
Exploring objc_Object, we know that objc_object is made up of isa_t ISA and member variables in memory. View the source code for ISA_t
union isa_t {
uintptr_t bits;
private:
Class cls;
public:
#if defined(ISA_BITFIELD)
struct {
ISA_BITFIELD; // defined in isa.h
};
#endif
};
Copy the code
- Isa is a
Union (common body)
- Isa in the new version of memory after optimization, through
A domain
The way from the originalA 64 - bit
It simply acts as a class pointer and becomes free space to store other information. For example, in the x86 architecture, the middle 44 bits store the address of the class pointer, and the other bits store the information of associated objects, weak references, hash tables, etc., to a greater extentSave memory space
. - Among them
ISA_MASK
As amask
In ISA_BITFIELDRedundant information about bit-fields
Filter out theshiftcls
, the value of the class pointer.
define ISA_MASK 0x00007ffffffffff8ULL
define ISA_BITFIELD
uintptr_t nonpointer : 1;
uintptr_t has_assoc : 1;
uintptr_t has_cxx_dtor : 1;
uintptr_t shiftcls : 44;
uintptr_t magic : 6;
uintptr_t weakly_referenced : 1;
uintptr_t unused : 1;
uintptr_t has_sidetable_rc : 1;
uintptr_t extra_rc : 8
Copy the code
We can see their flow
Graph TD object corresponds to objc_object --> objc_object is made up of ISA --> ISA points to objc_Class isa points to objc_Class --> Objc_Class inherits from objc_Object objc_Class inherits from objc_Object --> Objc_object is made of ISA
Prints ISA memory information
The isa of an object points to a class. What does the ISA of a class point to?
In this example we explore the memory of XXPerson
XXPerson *p = [XXPerson alloc];
NSLog(@"%@",p);
Copy the code
p
To print out the objectMemory address
x/4gx
Calculates the memory address to which the current object pointsFour adjacent memory addresses
p/x
Isa address & ISA_MASK calculatedThe pointer address of shiftcls (class object)
po
Print out the class objectDescription information
- According to the
Step 3
The calculated address of the class object,Repeat steps 2-4
- p->isa == p.class ==
0x0000000100008270
== XXPerson - p.class->isa == p.class.class ==
0x0000000100008248
== XXPerson - (p.class->isa)->isa == p.class.class.class ==
0x00007fff88c65ca0
== NSObject - ((p.class->isa)->isa)->isa == p.class.class.class.class ==
0x00007fff88c65ca0
== NSObject
Metalclass (metal Class)
The ISA of the class refers to the metaclass
We can see that the printed memory address of P.lass and p.class.class is different, but the description printed through Po is the same, which is XXPerson.
Open MacOView, search the symbol table for XXPerson, and find _OBJC_METACLASS_$_XXPerson, where the type corresponds to the metaclass ->isa
Root Metal class
The ISA of the metaclass refers to the root metaclass
The description printed by the root metaclass is NSObject, and after that isa points to 0x00007FFF88C65CA0, the description printed by Po is NSObject.
A metaclass
withNSObject metaclass
Address to point to0x00007fff88c65ca0
isconsistent
theA metaclass
withNSObject class
Address to point to0x00007fff88c65cc8
differentA metaclass isa
Pointing to orA metaclass
conclusion
The NSObject
Instances of the isa
–>class
Class of isa
–>The metaclass
Isa metaclass
–>A metaclass
Isa of the root metaclass
–>oneself
NSObject
NSObject
–>The NSObject class
The NSObject class
–>NSObject metaclass
NSObject metaclass
–>oneself
NSObject metaclass
namelyA metaclass
superclass
Metaclasses have inheritance relationships
Class pMetaClass = object_getClass(LGPerson.class);
Class psuperClass = class_getSuperclass(pMetaClass);
NSLog(@"%@ - %p",psuperClass,psuperClass);
Class tMetaClass = object_getClass(LGTeacher.class);
Class tsuperClass = class_getSuperclass(tMetaClass);
NSLog(@"%@ - %p",tsuperClass,tsuperClass);
Copy the code
Print the result
LGPerson is the parent class of LGTeacher. It can be seen from the printed results above that there is an inheritance relationship between metaclasses and the parent class of metaclasses is the metaclass of the parent class.
NSObject’s parent class is nil
Class nsuperClass = class_getSuperclass(NSObject.class);
NSLog(@"%@ - %p",nsuperClass,nsuperClass);
Copy the code
Print the result
The parent of the NSObject metaclass is the NSObject class
In the code
Class rnsuperClass = class_getSuperclass(metaClass);
NSLog(@"%@ - %p",rnsuperClass,rnsuperClass);
Copy the code
Print the result
This is the same address as the NSObject class that was printed up here, but metaclases are also classes, on the other hand, so in their inheritance diagram, they still end up pointing to NSObject, everything is NSObject.
A diagram of class and metaclass inheritance
Apple official documentation ISA goes bitmap and class, metaclass inheritance diagram
class_data_bits_t bits
First, let’s look at the objc_class code for the metaclass
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 flags
Copy the code
Class_data_bits_t bits Indicates the location of an address
Methods, member variables, protocols, and so on are stored in bits. We can use address offsets to locate bits in class objects. What we know is that class objects inherit from ObjC_Object, so the first member variable isa is 8 bytes, superclass is 8 bytes, However, we do not know the size of the cache_t cache. View the source code, by removing methods, global variables and other objects do not take up memory space code, extract the following part of the code
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};Copy the code
Since the lower part of the structure is a union and shares memory, simple calculations show that cache_t cache occupies 16 bytes of memory 8 + 8. Add the isa and superclass above to the class_datA_bits_t bits address offset by 32 bytes
Member variable information
Perform the following steps to print the memory
x/4gx
Lgperson.class, to get the head of memory0x100008380
p/x 0x100008380 + 0x20
, the offset memory is obtained0x00000001000083a0
- Strong type p
(class_data_bits_t *)0x00000001000083a0
, the LLDB variable $97 is obtained - through
p $97->data()
To obtainclass_data_bits_t bits
Class_rw_t *) $98 = 0x0000000101233CA0 - p
$98->properties()
Gets class member information
(const property_array_t) $100 = {
list_array_tt<property_t, property_list_t, RawPtr> = {
= {
list = {
ptr = 0x0000000100008260
}
arrayAndFlag = 4295000672
}
}
}
Copy the code
- p
$100.list
- p
$101.ptr
- p
* $113
p *$113
(property_list_t) $114 = {
entsize_list_tt<property_t, property_list_t, 0, PointerModifierNop> = (entsizeAndFlags = 16, count = 2)
}
Copy the code
- The print result is an array, so it passes
get
Method, p$114.get(0)
Print memory
(property_t) $115 = (name = "name", attributes = "T@\"NSString\",C,N,V_name")
Copy the code
methods
x/4gx
Lgperson. class, which prints the memory address of the class object
0x100008380: 0x00000001000083a8 0x000000010036a140
0x100008390: 0x00000001012340f0 0x0002802800000003
Copy the code
- Enter P /x 0x100008380 +
0x20
To obtainClass_data_bits_t bits Specifies the offset address of 32 bytes
$117 = 0x00000001000083a0
Copy the code
- Enter p (class_datA_bits_t *) 0x00000001000083A0 to strongly change the type to
Class_data_bits_t pointer
(class_data_bits_t *) $118 = 0x00000001000083a0
Copy the code
- Type p $119 – >
methods()
To obtainMethods information
(const method_array_t) $120 = {
list_array_tt<method_t, method_list_t, method_list_t_authed_ptr> = {
= {
list = {
ptr = 0x0000000100008160
}
arrayAndFlag = 4295000416
}
}
}
Copy the code
- Type p $120. The list
(const method_list_t_authed_ptr<method_list_t>) $121 = {
ptr = 0x0000000100008160
}
Copy the code
- p $121.ptr
(method_list_t *const) $122 = 0x0000000100008160
Copy the code
- Type p * $122
(method_list_t) $123 = {
entsize_list_tt<method_t, method_list_t, 4294901763, method_t::pointer_modifier> = (entsizeAndFlags = 27, count = 6)
}
Copy the code
- Type p $123.
get(0)
.big()
, includingget(0)
To get the first element of the array’s method_t,big()
Print method information
(method_t::big) $125 = {
name = "sayNB"
types = 0x0000000100003f77 "v16@0:8"
imp = 0x0000000100003d40 (KCObjcBuild`-[LGPerson sayNB])
}
Copy the code