Summary of ios low-level articles
1. Objects, ISA, classes and metaclasses
Concept of 1.1.
- each
Objects have an ISA
When the object allocates memory, the memory of0 to 7 bytes
What’s stored isIsa information
- Objects are contained in the ISA of objects
Belongs to the class
The information of - There is also an ISA for each class, and there is also a class memory
0 to 7 bytes
Because theA class is also an object
.Class is an object of a metaclass
Metaclasses are rightClass object description
, just as a class is a description of a common instance object,Classes belong to metaclasses
- metaclass
Definition and Creation
By compilingTranslation is done
, metaclasses are associated with classes, names andThe name of the class of the same name
. The root metaclass of NSObject
Point to theNSObject metaclass
.The ISA of the root metaclass points to itself
The address of the root metaclass is 0x00000001003340F0 and the isa & Mask of the root metaclass = ISA (0x00000001003340F0&0x00007ffffffffff8ull = 0x00000001003340F0), verifies that the root metaclass isa points to itself
1.2 Inheritance relationship
- In the OC,
NSObject's parent class is nil
If theClass has inheritance
Department,Class metaclasses also have inheritance relationships
Such as:
When you have a Student class that inherits from Person, and a Person class that inherits from NSObject, the Student metaclass inherits from the Person metaclass, and the Person metaclass inherits from NSObject, and the metaclass of NSObject is NSObject itself
-
Inheritance relationships between classes:
Class (ttf_subclass)
Inherited fromsuperClass
superClass
Inherited fromRoot Class
, where the root class refers toNSObject
The root class
Inherited fromnil
, soThe root class
namelyNSObject
Can be understood asOrigin of all things
, that is, out of thin air
-
Metaclasses also have inheritance. The inheritance relationship between metaclasses is as follows:
SubClass metaclass (Metal SubClass)
Inherited fromSuperClass (metal SuperClass)
SuperClass (metal SuperClass)
Inherited fromRoot metal Class
Root Metal Class
Inheritance inRoot class
, where the root class refers toNSObject
- Object, class, metaclass
Inheritance relationships
: The inheritance relationship isAs opposed to classes and metaclasses
.There is no inheritance relationship between objects
Photo from LG-Cooci teacher
Therefore,**The placement of ISA
** The figure is as follows:
Instance of Subclass
theisa
Point to theClass (class)
Class object (class)
isa
Point to theMeta Classes
Meta Classes
theisa
Point to theRoot Metal class
Root Metal class
的isa
Pointing to itoneself
In itself, formThe closed loop
Here,A metaclass
isNSObject
Example analysis: Person inherits from NSObject, Student inherits from Person
-
Isa routing chain (two)
- Student’s ISA chain:
Student --> student --> student --> NSObject --> NSObject --> NSObject --> NSObject
- Isa bitmap for Person:
Person --> person --> Person --> NSObject --> NSObject --> person --> person --> Person --> NSObject
- Student’s ISA chain:
-
Superclass Chain (two)
- Class inheritance chain:
Student --> Person --> NSObject --> nil
- Metaclass inheritance chain:
Student --> Person --> NSObject --> NSObject --> nil
- Class inheritance chain:
Only one copy of the 1.3 class exists in memory after it is compiled
//MARK: - Analyze the number of classes in memory
void lgTestClassNum(){
Class class1 = [HTPerson class];
Class class2 = [HTPerson alloc].class;
Class class3 = object_getClass([HTPerson alloc]);
Class class4 = [HTPerson alloc].class;
NSLog(@"\n%p-\n%p-\n%p-\n%p",class1,class2,class3,class4);
/* The result is 0x100008100-0x100008100-0x100008100-0x100008100 */
}
Copy the code
In the code above, we create three LGPerson class objects in three different ways, but the address of the three class objects is exactly the same, indicating that the class has only one memory.
Note: Special NSObjec class
// NSObject instance object
NSObject *object1 = [NSObject alloc];
/ / NSObject class
Class class = object_getClass(object1);
/ / NSObject metaclass
Class metaClass = object_getClass(class);
// NSObject root metaclass
Class rootMetaClass = object_getClass(metaClass);
// NSObject Root metaclass
Class rootRootMetaClass = object_getClass(rootMetaClass);
NSLog(@"\n%p instance object \n%p class \n%p metaclass \n%p root metaclass \n%p root metaclass",object1,class,metaClass,rootMetaClass,rootRootMetaClass);
/* Output: 0x10070D950 Instance object 0x100357140 Class 0x1003570F0 metaclass 0x1003570F0 Root metaclass 0x1003570F0 Root metaclass */
Copy the code
There’s only one NSObject class in memory, and the metaclass of NSObject has the same name as the class, and there’s one, and the metaclass of NSObject has the same metaclass, the root metaclass, the root metaclass, and the ISA of the metaclass of NSObject points to itself
2 objc_object and objc_class
All classes are objects of objC_class, which inherits from the structure objc_Object
// Note: the source code is from objC4-781 objc_runtime_new.h
struct objc_class : objc_object {
// Class ISA;
Class superclass;
cache_t cache;
class_data_bits_t bits;
class_rw_t *data(a) const {
return bits.data(a); }void setData(class_rw_t *newData) {
bits.setData(newData);
}
/ /...
}
Copy the code
Note: source code from objC4-781 objC_runtime_new.h
What is the relationship between objc_class and objc_Object?
The structure type objc_class inherits from objc_Object, which is also a structure and has an ISA property, so objc_class also has an ISA property
In mian. CPP, the ISA in NSObject is defined at the bottom by Class, where the underlying encoding of Class comes from the objc_class type, so NSObject also has isa attributes
NSObject isa class that initializes an instance object, objc, which satisfies the properties of objc_object (that is, it has the isa property), mainly because isa is inherited from objc_class by NSObject, Objc_class inherits from Objc_Object, which has an ISA property. So objects have an ISA, and ISA stands for pointing, from the current objc_Object
Objc_object is the current root object, and all objects have the property objc_Object, which has the ISA property
- Objc_object is
The root object
, is a structure, objc_ObjectContains an ISA
SoMetaclasses, classes, and objects all have ISA
struct objc_object {
Class _Nonnull isa OBJC_ISA_AVAILABILITY;
};
Copy the code
Objc_object relation to objects:
All objects are instantiated from the objc_Object template; The root class of the OC-side class is NSObject, and the underlying template for NSObject is objC_Object
OC code is compiled into C++ code, and the underlying template for Class(the type of the isa pointer) in OC is objc_class:
typedef struct objc_class *Class;
Three types of structural analysis
3.1 Memory Offset
Contiguous data addresses exist in stack memory:
- ordinary
A variable of the basic type
Address offset of
int a = 10;
int b = 10;
printf("%d--%p\n",a,&a);
printf("%d--%p\n",b,&b);
/* Prints the result: 10-- 0x7ffeefBff4f0 10-- 0x7FFeefBff4F4 */
Copy the code
Int b = 10; int a = 10; int b = 10; int b = 10;
A and B are stored on the stack, and their addresses are contiguous. The addresses correspond to the memory space required by the type of A. In this example, A is an int, and all the addresses of A and B differ by 4 bytes
Class object variable
Address offset
LGPerson *p1 = [LGPerson alloc]; // p1 is the pointer
LGPerson *p2 = [LGPerson alloc];
NSLog(@"%@ -- %p\n", p1, &p1);
NSLog(@"%@ -- %p\n", p2, &p2);
/* Print result:
-- 0x7ffeefbff4e0
-- 0x7ffeefbff4e8 */
Copy the code
[LGPerson alloc] [LGPerson alloc] [LGPerson alloc] [LGPerson alloc] [LGPerson alloc] [LGPerson alloc
Pointer to an array
Address offset
int c[4] = {1.2.3.4};
int *d = c;
NSLog(@"%p -- %p - %p",&c[0], &c[1],&c[2]);
NSLog(@"%p -- %p - %p", d, d+1, d+2);
/* 0x7ffeefbff4e0 -- 0x7ffeefbff4e4 - 0x7ffeefbff4e8 0x7ffeefbff4e0 -- 0x7ffeefbff4e4 - 0x7ffeefbff4e8 */
Copy the code
The addresses of array elements are contiguous, and the difference between &c[0] and &c[1] is 4 bytes, and the difference between &c[1] and &c[2] is 4 bytes, depending on the data type stored
Other elements in the array can be retrieved by using the first address + the offset, where the offset is the subscript of the array. The actual address is the first address + the offset * number of bytes of the data type
3.2 Objc_class Class structure
Objc4-781 Project Headers/objc_runtime-new.h Define the objc_class structure as follows:
-
Isa attribute: Isa of Class type, 8 bytes
-
Superclass property: Class type, Class is an objc_object pointer, 8 bytes
-
Cache property: Cache_t Object of the structure type, occupying 16 bytes
struct cache_t {
#if CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_OUTLINED
explicit_atomic<struct bucket_t* > _buckets; // is a structure pointer type of 8 bytes
explicit_atomic<mask_t> _mask; // mask_t is of type mask_t, which is the 4-byte alias of an unsigned int
#elif CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_HIGH_16
explicit_atomic<uintptr_t> _maskAndBuckets; // Is a pointer, accounting for 8 bytes
mask_t _mask_unused; // is of type mask_t, which is an alias of the uint32_t type definition and takes up 4 bytes
#if __LP64__
uint16_t _flags; // is of the uint16_t type, uint16_t is an alias for unsigned short and takes up 2 bytes
#endif
uint16_t _occupied; // is of the uint16_t type, uint16_t is an alias for unsigned short and takes up 2 bytes
Copy the code
#if branches compute memory
Buckets is struct bucket_t *, which is an 8-byte structure pointer
Mask is of type mask_t, and mask_t, the alias of an unsigned int, is 4 bytes
_flags is of type uint16_t and takes up 2 bytes
_occupied is of the uint16_t type, comprising 2 bytes
Elseif branches compute memory
_maskAndBuckets is a uintptr_t type and is a pointer with 8 bytes
_mask_unused is of the mask_t type, which is an alias to the uint32_t type definition and takes up four bytes
_flags is of type uint16_t and takes up 2 bytes
_occupied is of the uint16_t type, comprising 2 bytes
bits
Attribute: class_datA_bits_t. It is a structure. The size of the structure’s memory needs to be determined according to its internal attributesBits first address
3.3 Obtaining the Bits Address
3.3.1 throughThe first address of the class is shifted by 32 bytes
Get class_data_bits_t * :
(lldb) p/x LGPerson.class
(Class) $0 = 0x0000000100002240 LGPerson
(lldb) x/4gx 0x0000000100002240
0x100002240: 0x0000000100002218 0x0000000100334140
0x100002250: 0x00000001006847d0 0x000580240000000f
(lldb) p 0x0000000100002218 & 0x00007ffffffffff8ULL
(unsigned long long) The $1 = 4294976024
(lldb) p/x 0x0000000100002218 & 0x00007ffffffffff8ULL
(unsigned long long) $2 = 0x0000000100002218
(lldb) p (class_data_bits_t*)0x0000000100002238
(class_data_bits_t *) $3 = 0x0000000100002238
Copy the code
3.3.2 class_datA_bits_t Gets the pointer to the class_rw_T structure by using the data() method
- Class_data_bits_t structure
- Command to obtain:
(lldb) p/x LGPerson.class
(Class) $0 = 0x0000000100002240 LGPerson
(lldb) x/4gx 0x0000000100002240
0x100002240: 0x0000000100002218 0x0000000100334140
0x100002250: 0x00000001006847d0 0x000580240000000f
(lldb) p 0x0000000100002218 & 0x00007ffffffffff8ULL
(unsigned long long) The $1 = 4294976024
(lldb) p/x 0x0000000100002218 & 0x00007ffffffffff8ULL
(unsigned long long) $2 = 0x0000000100002218
(lldb) p (class_data_bits_t*)0x0000000100002238
(class_data_bits_t *) $3 = 0x0000000100002238
(lldb) p $3->data()
(class_rw_t *) $4 = 0x0000000100683dc0
(lldb) p $4->methods()
Copy the code
3.3.4 Class_rw_t Obtains the method list, attribute list, and protocol list from methods(),properties(), and protocols()
- Class_rw_t structure definition
- Command to get a list of class methods (class methods are stored in metaclass, retrieved from metaclass)
(lldb) p/x LGPerson.class
(Class) $0 = 0x0000000100002240 LGPerson
(lldb) x/4gx 0x0000000100002240
0x100002240: 0x0000000100002218 0x0000000100334140
0x100002250: 0x00000001006847d0 0x000580240000000f
(lldb) p 0x0000000100002218 & 0x00007ffffffffff8ULL
(unsigned long long) The $1 = 4294976024
(lldb) p/x 0x0000000100002218 & 0x00007ffffffffff8ULL
(unsigned long long) $2 = 0x0000000100002218
(lldb) p (class_data_bits_t*)0x0000000100002238
(class_data_bits_t *) $3 = 0x0000000100002238
(lldb) p $3->data()
(class_rw_t *) $4 = 0x0000000100683dc0
(lldb) p $4->methods()
(const method_array_t) A $5 = {
list_array_tt<method_t, method_list_t> = {
= {
list = 0x0000000100002090
arrayAndFlag = 4294975632
}
}
}
(lldb) p A $5.list
(method_list_t *const) $6 = 0x0000000100002090
(lldb) p *$6
(method_list_t) $7 = {
entsize_list_tt<method_t, method_list_t, 3> = {
entsizeAndFlags = 26
count = 1
first = {
name = "sayBye"
types = 0x0000000100000f6e "v16@0:8"
imp = 0x0000000100000d20 (KCObjc`+[LGPerson sayBye])
}
}
}
(lldb) p $7.get(0)
(method_t) $8 = {
name = "sayBye"
types = 0x0000000100000f6e "v16@0:8"
imp =
Copy the code
- Command to get object methods (from the class structure)
lldb) p/x LGPerson.class
(Class) $0 = 0x0000000100002240 LGPerson
(lldb) p/x (class_data_bits_t *)(0x0000000100002260)
(class_data_bits_t *) The $1 = 0x0000000100002260
(lldb) p/x The $1->data()
(class_rw_t *) $2 = 0x0000000100656070
(lldb) p/x $2->methods()
(const method_array_t) $3 = {
list_array_tt<method_t, method_list_t> = {
= {
list = 0x00000001000020f8
arrayAndFlag = 0x00000001000020f8
}
}
}
(lldb) p $3.list
(method_list_t *const) $4 = 0x00000001000020f8
(lldb) p *$4
(method_list_t) $8 = {
entsize_list_tt<method_t, method_list_t, 3> = {
entsizeAndFlags = 16
count = 2
first = {
name = "name"
types = 0x0000000100000ee1 "T@\"NSString\",C,N,V_name"
imp = 0x0000000100000ef9 ("age")
}
}
}
(lldb)p $8.get(0)
(method_t) $9 = {
name = "name"
types = 0x0000000100000ee1 "T@\"NSString\",C,N,V_name"
imp = 0x0000000100000ef9 ("age")
}
(lldb) p $8.get(1)
(method_t) $10 = {
name = "age"
types = 0x0000000100000efd "Tq,N,V_age"
imp = 0x0000000100002240 ((void *)0x0000000100002218: LGPerson)
}
(lldb) p $8.get(2)
Assertion failed: (i < count), functionGet the file/Users/wangqiao/Desktop/iOSV9.0 / can compile objc source/runtime/objc runtime - new. H, line 434. Error: Execution was interrupted, reason: signal SIGABRT. The process has been returned to the state before expression evaluation.Copy the code
- Command to get object properties (from the class structure)
(lldb) p/x LGPerson.class
(Class) $0 = 0x0000000100002240 LGPerson
(lldb) p/x (class_data_bits_t *)(0x0000000100002260)
(class_data_bits_t *) The $1 = 0x0000000100002260
(lldb) p/x The $1->data()
(class_rw_t *) $2 = 0x0000000100656070
(lldb) p/x $2->properties()
(const property_array_t) A $5 = {
list_array_tt<property_t, property_list_t> = {
= {
list = 0x00000001000021d8
arrayAndFlag = 0x00000001000021d8
}
}
}
(lldb) p/x A $5.list
(property_list_t *const) $6 = 0x00000001000021d8
(lldb) p *$6
(property_list_t) $7 = {
entsize_list_tt<property_t, property_list_t, 0> = {
entsizeAndFlags = 16
count = 2
first = (name = "name", attributes = "T@\"NSString\",C,N,V_name")
}
}
(lldb) p $7.get(0)
(property_t) $11 = (name = "name", attributes = "T@\"NSString\",C,N,V_name")
(lldb) p $7.get(1)
(property_t) $12 = (name = "age", attributes = "Tq,N,V_age")
(lldb) p $7.get(2)
Assertion failed: (i < count), functionGet the file/Users/wangqiao/Desktop/iOSV9.0 / can compile objc source/runtime/objc runtime - new. H, line 434. Error: Execution was interrupted, reason: signal SIGABRT. The process has been returned to the state before expression evaluation. (lldb)Copy the code
- Command to get a list of properties (without member variables)
- The address of bits is 32 bytes cheaper than the address of the objc_class class
class_data_bits_t
The address of theclass_data_bits_t*
- in
class_data_bits_t
In the calldata()
To obtain theclass_rw_t
The address of theclass_rw_t*
class_rw_t
Struct callro()
To obtain theclass_ro_t
The address of the ` class_ro_t *)- The baseProperties member variable in the class_ro_t structure is the address of the property list
- The address of bits is 32 bytes cheaper than the address of the objc_class class
- Obtain the value from the LLVM command
Property list
For the same reasonGets a list of member variables
andMethods list
)
- Get ivars with bits->data->ro (containing attributes and member variables)
(lldb) x/4gx person
0x100647220: 0x011d8001000083dd 0x0000000000000000
0x100647230: 0x0000000000000000 0x0000000000000000
(lldb) p 0x011d8001000083dd & 0x00007ffffffffff8ULL
(unsigned long long) The $1 = 4295001048
(lldb) p/x 0x011d8001000083dd & 0x00007ffffffffff8ULL
(unsigned long long) $2 = 0x00000001000083d8
(lldb) p (class_data_bits_t *)0x00000001000083f8
(class_data_bits_t *) $3 = 0x00000001000083f8
(lldb) p $3->data()
(class_rw_t *) $4 = 0x0000000100646670
(lldb) p $4->ro()
(const class_ro_t *) A $5 = 0x0000000100008098
(lldb) p *A $5
(const class_ro_t) $6 = {
flags = 388
instanceStart = 8
instanceSize = 72
reserved = 0
= {
ivarLayout = 0x0000000100003ede "\x01\x11\x13"
nonMetaclass = 0x0000000100003ede
}
name = {
std::__1::atomic<const char *> = "HTPerson" {
Value = 0x0000000100003ed5 "HTPerson"
}
}
baseMethodList = 0x00000001000080e0
baseProtocols = 0x0000000000000000
ivars = 0x0000000100008190
weakIvarLayout = 0x0000000000000000
baseProperties = 0x0000000100008298
_swiftMetadataInitializer_NEVER_USE = {}
}
(lldb) p $6.ivars
(const ivar_list_t *const) $7 = 0x0000000100008190
(lldb) p $7->get(0)
(ivar_t) $8 = {
offset = 0x0000000100008370
name = 0x0000000100003eec "hobby"
type = 0x0000000100003f60 "@\"NSString\""
alignment_raw = 3
size = 8
}
(lldb) p $7->get(1)
(ivar_t) $9 = {
offset = 0x0000000100008378
name = 0x0000000100003ef2 "weight"
type = 0x0000000100003f6c "i"
alignment_raw = 2
size = 4
}
(lldb) p $7->get(2)
(ivar_t) $10 = {
offset = 0x0000000100008380
name = 0x0000000100003ef9 "objc"
type = 0x0000000100003f6e "@\"NSObject\""
alignment_raw = 3
size = 8
}
(lldb) p $7->get(3)
(ivar_t) $11 = {
offset = 0x0000000100008388
name = 0x0000000100003efe "sex"
type = 0x0000000100003f7a "c"
alignment_raw = 0
size = 1
}
(lldb) p $7->get(4)
(ivar_t) $12 = {
offset = 0x0000000100008390
name = 0x0000000100003f02 "intersting"
type = 0x0000000100003f60 "@\"NSString\""
alignment_raw = 3
size = 8
}
(lldb) p $7->get(5)
(ivar_t) $13 = {
offset = 0x0000000100008398
name = 0x0000000100003f0d "_name"
type = 0x0000000100003f60 "@\"NSString\""
alignment_raw = 3
size = 8
}
(lldb) p $7->get(6)
(ivar_t) $14 = {
offset = 0x00000001000083a0
name = 0x0000000100003f13 "_nickname"
type = 0x0000000100003f60 "@\"NSString\""
alignment_raw = 3
size = 8
}
(lldb) p $7->get(7)
(ivar_t) $15 = {
offset = 0x00000001000083a8
name = 0x0000000100003f1d "_age"
type = 0x0000000100003f7c "q"
alignment_raw = 3
size = 8
}
Copy the code
3.4 OC layer obtains instance variable names and attribute names through Runtime
void lgObjc_copyIvar_copyProperies(Class pClass){
unsigned int count = 0;
Ivar *ivars = class_copyIvarList(pClass, &count);
for (unsigned int i=0; i < count; i++) {
Ivar const ivar = ivars[i];
// Get the instance variable name
const char*cName = ivar_getName(ivar);
NSString *ivarName = [NSString stringWithUTF8String:cName];
LGLog(@"class_copyIvarList:%@",ivarName);
}
free(ivars);
unsigned int pCount = 0;
objc_property_t *properties = class_copyPropertyList(pClass, &pCount);
for (unsigned int i=0; i < pCount; i++) {
objc_property_t const property = properties[i];
// Get the attribute name
NSString *propertyName = [NSString stringWithUTF8String:property_getName(property)];
LGLog(@"class_copyProperiesList:%@",propertyName);
}
free(properties);
}
Copy the code