前言
关于
alloc
已经探索完了 接下来我们来看一下isa
分析到元类
一.isa
走位图和继承链
一.lldb
调试
先搞一波运行起来demo
LGPerson *test = [LGPerson alloc];
断点这里 NSLog(@"%@",test);
复制代码
1.lldb
终端输入如下命令得到实例对象地址
po test
<LGPerson: 0x10500de60> 得到实例对象内存地址
复制代码
2.打印内存
x/4gx 0x10500de60
0x10500de60(内存地址): 0x011d800100008365(如何能证明这个是isa) 0x0000000000000000
0x10500de70: 0x0000000000000000 0x0000000000000000
复制代码
3.得到类isa
指向的地址
p/x 0x011d800100008365 & 0x00007ffffffffff8
(unsigned long long) $2 = 0x0000000100008360 (获取类的内存地址)
复制代码
4.打印类名称
po 0x0000000100008360
LGPerson(得到类名称)
复制代码
到此我们可以探索到实例对象的
isa->(LGPerson:0x0000000100008360)
类 那么类对象的isa指向哪里呢?我们继续走你
5.打印类的内存
x/4gx 0x0000000100008360
0x100008360: 0x0000000100008338(isa) 0x00007fff88bdfcc8
0x100008370: 0x0000000100641640 0x0002802c00000003
复制代码
6.得到类isa
指向的地址
p/x 0x0000000100008338 & 0x00007ffffffffff8
$8 = 0x0000000100008338(获取类的内存地址)
复制代码
7.打印类名称
po 0x0000000100008338
LGPerson(得到类名称)
复制代码
到此我们可以探索到
(LGPerson:0x0000000100008360)的isa->(LGPerson:0x0000000100008338
(这是什么东东))
8.运行另外一个demo
Class class1 = [LGPerson class];
Class class2 = [LGPerson alloc].class;
Class class3 = object_getClass([LGPerson alloc]);
Class class4 = [LGPerson alloc].class;
NSLog(@"\n%p-\n%p-\n%p-\n%p",class1,class2,class3,class4);
打印结果地址: 0x100008360-
0x100008360-
0x100008360-
0x100008360
和 LGPerson:0x0000000100008360 对的上
复制代码
9.看一下mach-o
文件 LGPerson:0x0000000100008338
应该是元类
到此我们可以探索到
(LGPerson:0x0000000100008338)的isa
又指向哪里呢 继续走你
10.打印元类的内存
x/4gx 0x0000000100008338
0x100008338: 0x00007fff88bdfca0 (isa)0x00007fff88bdfca0
0x100008348: 0x00000001006419d0 0x0002e03500000003
复制代码
11.得到元类isa
指向的地址
p/x 0x00007fff88bdfca0 & 0x00007ffffffffff8ULL
(unsigned long long) $10 = 0x00007fff88bdfca0(获取类的内存地址)
复制代码
12.打印类名称
po 0x00007fff88bdfca0
NSObject
复制代码
到此我们可以探索到(LGPerson:0x0000000100008338)的isa 指向根元类(NSObject) 那么根元类的isa又指向哪里呢
13.打印根元类的内存
x/4gx 0x00007fff88bdfca0
0x7fff88bdfca0: 0x00007fff88bdfca0 0x00007fff88bdfcc8
0x7fff88bdfcb0: 0x0000000100641b10 0x0003e03100000007
复制代码
14.得到根元类isa
指向的地址
p/x 0x00007fff88bdfca0 & 0x00007ffffffffff8
(unsigned long long) $12 = 0x00007fff88bdfca0(获取类的内存地址)
复制代码
15.打印类名称
po 0x00007fff88bdfca0
NSObject
复制代码
到此我们可以探索到根元类
(NSObject)的isa
指向了自己
总结:对象
isa
-> 类(LGPerson:0x0000000100008360) isa
-> 元类(LGPerson:0x0000000100008338) isa
-> 根元类(NSObject) isa
-> 根元类
16.我们直接打印NSObject.class
p/x NSObject.class
(Class) $14 = 0x00007fff88bdfcc8 NSObject
打印类的内存
x/4gx 0x00007fff88bdfcc8
0x7fff88bdfcc8: 0x00007fff88bdfca0 0x0000000000000000
0x7fff88bdfcd8: 0x0000000105007bd0 0x0002801000000003
打印类的地址
p/x 0x00007fff88bdfca0 & 0x00007ffffffffff8
(long) $15 = 0x00007fff88bdfca0
打印类的名称
po 0x00007fff88bdfca0
NSObject
复制代码
总结:根类
isa
-> 根元类isa
->根元类
二.代码调试isa
走向
1.我们创建的NSObject
实例对象演示:
2.我们创建LGPerson
实例对象演示:
3.因为LGTeacher
继承于LGPerson
,LGTeacher
实例对象演示:
下面我们探索一下继承的
isa
是怎么样指向的 直接上代码
三.代码调试isa
继承走向
一.类继承的isa
指向
1.我们先看一下 NSObject.class
的isa
指向
2.我们看一下 LGPerson.class
的isa
指向
3.我们看一下 LGTeacher.class
的isa
指向
4.我们看一下 LGXiaowen.class
的isa
指向
二.元类继承的isa
指向
1.我们先看一下 NSObject.class
元类的isa
指向
2.我们看一下 LGPerson.class
元类的isa
指向
3.我们看一下 LGTeacher.class
元类的isa
指向
4.我们看一下 LGXiaowen.class
元类的isa
指向
结合上面分析得到如下结论如下图
二.源码分析类的结构
三.指针和内存平移
// 数组指针
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; i++) {
int value = *(d+i);
NSLog(@"%d",value);
}
打印得出:002-内存偏移[38980:1658739] 0x7ffeefbff3c0 - 0x7ffeefbff3c0 - 0x7ffeefbff3c4
2021-06-20 13:41:36.896925+0800 002-内存偏移[38980:1658739] 0x7ffeefbff3c0 - 0x7ffeefbff3c4 - 0x7ffeefbff3c8
2021-06-20 13:41:37.939247+0800 002-内存偏移[38980:1658739] 1
2021-06-20 13:42:19.343718+0800 002-内存偏移[38980:1658739] 2
2021-06-20 13:42:19.343888+0800 002-内存偏移[38980:1658739] 3
2021-06-20 13:42:19.343959+0800 002-内存偏移[38980:1658739] 4
复制代码
根据指针内存的平移获取数组相应的取值 这样我们就可以根据类的首地址进行平台获取里面成员变量的值
四.类的结构内存计算
x/4gx LGPerson.class
0x100008380: 0x00000001000083a8 0x000000010036a140
0x100008390: 0x0000000101052a80 0x0002802800000003
0x00000001000083a8:对应Class ISA
0x000000010036a140:对应Class superclass
0x0000000101052a80:对应cache_t cache
0x0002802800000003:class_data_bits bits
复制代码
想要获取到bits 就的通过首地址平移这些长度ISA(8字节)
->superclass(8字节)
->cache(多少呢)
cache = 8+8 = 16
所以平移到bits
需要移动32
五.lldb分析类的结构
1.在class_rw_t
里面查找LGPerson
的成员变量
(lldb) x/4gx LGPerson.class
0x100008380: 0x00000001000083a8 0x000000010036a140
0x100008390: 0x0000000100764050 0x0002802800000003
(lldb) p (class_data_bits_t *) 0x1000083a0 //获取class_data_bits_t +32
(class_data_bits_t *) $1 = 0x00000001000083a0
(lldb) p $1->data() //获取 class_rw_t
(class_rw_t *) $2 = 0x0000000100764010
(lldb) p * $2 //查看 class_rw_t
(class_rw_t) $3 = {
flags = 2148007936
witness = 1
ro_or_rw_ext = {
std::__1::atomic<unsigned long> = {
Value = 4295000344
}
}
firstSubclass = nil
nextSiblingClass = NSUUID
}
//获取属性
(lldb) p $2.properties() //查看 class_rw_t.properties()
(const property_array_t) $4 = {
list_array_tt<property_t, property_list_t, RawPtr> = {
= {
`list` = {
ptr = 0x0000000100008260
}
arrayAndFlag = 4295000672
}
}
}
Fix-it applied, fixed expression was:
$2->properties()
(lldb) p $4.list //上面返回的
(const RawPtr<property_list_t>) $5 = {
`ptr` = 0x0000000100008260
}
(lldb) p $5.ptr
(property_list_t *const) $6 = 0x0000000100008260
(lldb) p *$6
(property_list_t) $7 = {
`entsize_list_tt`<property_t, property_list_t, 0, PointerModifierNop> = (entsizeAndFlags = 16, count = 2)
}
(lldb) p $7.get(0)
(property_t) $8 = (name = "name", attributes = "T@\"NSString\",C,N,V_name")
p $7.get(1)
(property_t) $9 = (name = "hobby", attributes = "T@\"NSString\",C,N,V_hobby")
获取对象实例方法
p $2.methods() //查看 class_rw_t.methods()
(const method_array_t) $10 = {
list_array_tt<method_t, method_list_t, method_list_t_authed_ptr> = {
= {
list = {
ptr = 0x0000000100008160
}
arrayAndFlag = 4295000416
}
}
}
Fix-it applied, fixed expression was:
$2->methods()
(lldb) p $10.list
(const method_list_t_authed_ptr<method_list_t>) $11 = {
ptr = 0x0000000100008160
}
(lldb) p $11.ptr
(method_list_t *const) $12 = 0x0000000100008160
(lldb) p *$12
(method_list_t) $13 = {
entsize_list_tt<method_t, method_list_t, 4294901763, method_t::pointer_modifier> = (entsizeAndFlags = 27, count = 6)
}
(lldb) p $13.get(0).big().name
(SEL) $14 = "hobby"
(lldb) p $13.get(1).big().name
(SEL) $15 = "sayNB"
(lldb) p $13.get(2).big().name
(SEL) $16 = "setHobby:"
(lldb) p $13.get(3).big().name
(SEL) $17 = "init"
(lldb) p $13.get(4).big().name
(SEL) $18 = "name"
(lldb) p $13.get(5).big().name
(SEL) $19 = "setName:"
(lldb) p $13.get(6).big().name
复制代码
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END