preface
In the last article, we saw that NSObject is made up of objc_class, so what information does objc_class contain, where do we store all the properties, methods, protocols that we normally use
Objc_class internal structure
Take a look at the source code:
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
class_rw_t *data() {
return bits.data();
}
void setData(class_rw_t *newData) { bits.setData(newData); }... }Copy the code
Objc_class contains isa, superclass, cache_t, class_data_bits_t, and class_data_bits_t. Class_data_bits_t stores class data and provides a method called data(). So let’s look at the return value class_rw_t of data
struct class_rw_t {
// Be warned that Symbolication knows the layout of this structure.
uint32_t flags;
uint32_t version;
const class_ro_t *ro;
method_array_t methods;
property_array_t properties;
protocol_array_t protocols;
Class firstSubclass;
Class nextSiblingClass;
char *demangledName;
Copy the code
It contains methods, properties, protocols, and ro attributes. Class_ro_t
struct class_ro_t {
uint32_t flags;
uint32_t instanceStart;
uint32_t instanceSize;
#ifdef __LP64__
uint32_t reserved;
#endif
const uint8_t * ivarLayout;
const char * name;
method_list_t * baseMethodList;
protocol_list_t * baseProtocols;
const ivar_list_t * ivars;
const uint8_t * weakIvarLayout;
property_list_t *baseProperties;
method_list_t *baseMethods() const {
returnbaseMethodList; }};Copy the code
There’s also some information about the class, so which one is actually storing the information? You can verify it in code
Code validation
You define a class that has variables, attributes, class methods, and instance methods
@interface LGPerson : NSObject{ NSString *hobby; } @property (nonatomic, copy) NSString *nickName; - (void)sayHello; + (void)sayHappy; LGPerson *person = [LGPerson alloc]; Class pClass = object_getClass(person); NSLog(@"% @", pClass);
}
Copy the code
Get class_rw_t
Open breakpoint debugging, we first output pClass address information
(lldb) x/4gx pClass
0x100001200: 0x001d8001000011d9 0x0000000100afd140
0x100001210: 0x00000001003a0270 0x0000000000000000
Copy the code
To get bits, we need to find the address
Isa // 8 bytes
Class superclass; // 8 bytes
cache_t cache; // 16 bytes
The bits address is offset by 32 bytes from the objc_class address 0x100001200, offset by 32 bytes from the objc_class address 0x100001220
(lldb) p (class_data_bits_t*)0x100001220
(class_data_bits_t *) The $1= 0x0000000100001220 // Get the class_rw_t pointer (LLDB) pThe $1->data()
(class_rw_t *) $2= 0x000000010183e7d0 // Get pointer contents (LLDB) p *$2
(class_rw_t) $3 = {
flags = 2148139008
version = 0
ro = 0x0000000100001178
methods = {
list_array_tt<method_t, method_list_t> = {
= {
list = 0x00000001000010c8
arrayAndFlag = 4294971592
}
}
}
properties = {
list_array_tt<property_t, property_list_t> = {
= {
list = 0x0000000100001160
arrayAndFlag = 4294971744
}
}
}
protocols = {
list_array_tt<unsigned long, protocol_list_t> = {
= {
list = 0x0000000000000000
arrayAndFlag = 0
}
}
}
firstSubclass = nil
nextSiblingClass = NSDate
demangledName = 0x0000000000000000
}
Copy the code
Get the list of methods in class_rw_t
As you can see, methods, properties are all here. Let’s try to look at the list of methods:
lldb) p $3.methods
(method_array_t) $8 = {
list_array_tt<method_t, method_list_t> = {
= {
list = 0x00000001000010c8
arrayAndFlag = 4294971592
}
}
}
(lldb) p $8.list
(method_list_t *) $9 = 0x00000001000010c8
(lldb) p *$9
(method_list_t) $10 = {
entsize_list_tt<method_t, method_list_t, 3> = {
entsizeAndFlags = 26
count = 3
first = {
name = "nickName"
types = 0x0000000100000f97 "@ @ 0:8 16"
imp = 0x0000000100000de0 (LGTest`-[LGPerson nickName] at LGPerson.h:16)
}
}
}
Copy the code
Get the information from ro
We got the content we wanted, but we wanted to find the internal property of Hobby, and found that it could not be found here. We just looked at the source code and found that ro also has information, so we continue to look
(lldb) p $3.ro
(const class_ro_t *) $4 = 0x0000000100001178
(lldb) p *$4
(const class_ro_t) A $5 = {
flags = 388
instanceStart = 8
instanceSize = 24
reserved = 0
ivarLayout = 0x0000000100000f59 "\x02"
name = 0x0000000100000f50 "LGPerson"
baseMethodList = 0x00000001000010c8
baseProtocols = 0x0000000000000000
ivars = 0x0000000100001118
weakIvarLayout = 0x0000000000000000
baseProperties = 0x0000000100001160
}
Copy the code
In addition to baseProperties, baseMethodList, baseProtocols, and Ivars, let’s verify the contents
(lldb) p A $5.ivars
(const ivar_list_t *const) $16 = 0x0000000100001118
(lldb) p *$16
(const ivar_list_t) $17 = {
entsize_list_tt<ivar_t, ivar_list_t, 0> = {
entsizeAndFlags = 32
count = 2
first = {
offset = 0x00000001000011c8
name = 0x0000000100000f7f "hobby"
type = 0x0000000100000faa "@\"NSString\""
alignment_raw = 3
size = 8
}
}
}
Copy the code
The Hobby property variable is found, and the list of methods is also available here. So, we know that the properties of the class, the instance methods, are stored here.
Class method store location
We find + (void)sayHappy; We haven’t found the storage yet, but we talked about classes that have metaclasses, is that going to be stored in metaclasses, code verification
void testInstanceMethod_classToMetaclass(Class pClass){
const char *className = class_getName(pClass);
Class metaClass = objc_getMetaClass(className);
Method method1 = class_getInstanceMethod(pClass, @selector(sayHello));
Method method2 = class_getInstanceMethod(metaClass, @selector(sayHello));
Method method3 = class_getInstanceMethod(pClass, @selector(sayHappy));
Method method4 = class_getInstanceMethod(metaClass, @selector(sayHappy));
NSLog(@"%p-%p-%p-%p",method1,method2,method3,method4);
NSLog(@"%s",__func__);
}
void testClassMethod_classToMetaclass(Class pClass){
const char *className = class_getName(pClass);
Class metaClass = objc_getMetaClass(className);
Method method1 = class_getClassMethod(pClass, @selector(sayHello));
Method method2 = class_getClassMethod(metaClass, @selector(sayHello));
Method method3 = class_getClassMethod(pClass, @selector(sayHappy));
Method method4 = class_getClassMethod(metaClass, @selector(sayHappy)); // ?
NSLog(@"%p-%p-%p-%p",method1,method2,method3,method4);
NSLog(@"%s",__func__);
}
Copy the code
The output is:
0x100002248-0x0-0x0-0x1000021e0
0x0-0x0-0x1000021e0-0x1000021e0
As you can see, class methods exist in the metaclass, we can also verify for ourselves
Current Class Information (LLDB) x/ 4GX pClass 0x1000023B0:0x001D800100002389 0x0000000100AFe140 0x1000023C0: 0x00000001003a1290 0x0000000000000000 // Get metaclass (LLDB) p 0x001D800100002389&0x00007ffffffff8 (long)The $1 = 4294976392
(lldb) po The $1LGPerson // Get the metaclass address (LLDB) x/4gxThe $10x100002388: 0x001d800100afe0f1 0x0000000100afe0f0 0x100002398: 0x000000010192AC00 0x0000000100000003 // Obtain the metaclass class_rw_t (LLDB) p (class_data_bits_t*)0x1000023a8 (class_data_bits_t*)$2 = 0x00000001000023a8
(lldb) p $2->data()
(class_rw_t *) $3 = 0x000000010192ab60
(lldb) p *$3
(class_rw_t) $4 = {
flags = 2685075456
version = 7
ro = 0x00000001000021f8
methods = {
list_array_tt<method_t, method_list_t> = {
= {
list = 0x00000001000021d8
arrayAndFlag = 4294975960
}
}
}
properties = {
list_array_tt<property_t, property_list_t> = {
= {
list = 0x0000000000000000
arrayAndFlag = 0
}
}
}
protocols = {
list_array_tt<unsigned long, protocol_list_t> = {
= {
list = 0x0000000000000000
arrayAndFlag = 0
}
}
}
firstSubclass = nil
nextSiblingClass = 0x00007fff95935900
demangledName = 0x0000000100001f80 "LGPerson"} // get the metaclass ro (LLDB) p$4.ro
(const class_ro_t *) A $5 = 0x00000001000021f8
(lldb) p *S5
error: use of undeclared identifier 'S5'
(lldb) p A $5
(const class_ro_t *) A $5 = 0x00000001000021f8
(lldb) p *A $5
(const class_ro_t) $6 = {
flags = 389
instanceStart = 40
instanceSize = 40
reserved = 0
ivarLayout = 0x0000000000000000
name = 0x0000000100001f80 "LGPerson"baseMethodList = 0x00000001000021d8 baseProtocols = 0x0000000000000000 ivars = 0x0000000000000000 weakIvarLayout = 0x0000000000000000 baseProperties = 0x0000000000000000} // Get the list of metaclass methods (LLDB) p$6.baseMethodList
(method_list_t *const) $7 = 0x00000001000021d8
(lldb) p *$7
(method_list_t) $8 = {
entsize_list_tt<method_t, method_list_t, 3> = {
entsizeAndFlags = 26
count = 1
first = {
name = "sayHappy"
types = 0x0000000100001f8b "v16@0:8"
imp = 0x0000000100001bc0 (LGTest`+[LGPerson sayHappy] at LGPerson.m:17)
}
}
}
Copy the code
As you can see from the information, class methods do exist in metaclasses.