前言
关于
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:对应cache_t cache
想要获取到bits 就的通过首地址平移这些长度ISA(8字节)->superclass(8字节)->cache(多少呢)
cache = 8+8 = 16 所以平移到bits需要移动32
五.lldb分析类的结构
1.获取LGPerson的属性
在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 = 4)
}
(lldb) p $7.get(0)
(property_t) $8 = (name = "name", attributes = "T@\"NSString\",C,N,V_name")
(lldb) p $7.get(1)
(property_t) $9 = (name = "hobby", attributes = "T@\"NSString\",C,V_hobby")
(lldb) p $7.get(2)
(property_t) $10 = (name = "desc", attributes = "T@\"NSString\",V_desc")
(lldb) p $7.get(3)
(property_t) $11 = (name = "idcard", attributes = "T@\"NSString\",N,V_idcard")
2.获取对象实例方法
(lldb) p/x LGPerson.class
(Class) $0 = 0x0000000100008920 LGPerson
(lldb) p (class_data_bits_t *) 0x0000000100008940 //获取class_data_bits_t
(class_data_bits_t *) $1 = 0x0000000100008940
(lldb) p $1->data()
(class_rw_t *) $2 = 0x0000000100724a80 //获取 class_rw_t
(lldb) p $2.methods()
(const method_array_t) $3 = {
list_array_tt<method_t, method_list_t, method_list_t_authed_ptr> = {
= {
list = {
ptr = 0x00000001000081f8
}
arrayAndFlag = 4295000568
}
}
}
Fix-it applied, fixed expression was:
$2->methods()
(lldb) p $3.list.ptr
(method_list_t *const) $4 = 0x00000001000081f8
(lldb) p * $4
(method_list_t) $5 = {
entsize_list_tt<method_t, method_list_t, 4294901763, method_t::pointer_modifier> = (entsizeAndFlags = 27, count = 10)
}
(lldb) p $5.get(0).big()
(method_t::big) $6 = {
name = "hobby"
types = 0x0000000100003e78 "@16@0:8"
imp = 0x0000000100003aa0 (KCObjcBuild`-[LGPerson hobby])
}
(lldb) p $5.get(1).big()
(method_t::big) $7 = {
name = "sayNB"
types = 0x0000000100003e80 "v16@0:8"
imp = 0x0000000100003a30 (KCObjcBuild`-[LGPerson sayNB])
}
(lldb) p $5.get(2).big()
(method_t::big) $8 = {
name = "setHobby:"
types = 0x0000000100003ec4 "v24@0:8@16"
imp = 0x0000000100003ad0 (KCObjcBuild`-[LGPerson setHobby:])
}
(lldb) p $5.get(3).big()
(method_t::big) $9 = {
name = "idcard"
types = 0x0000000100003e78 "@16@0:8"
imp = 0x0000000100003b40 (KCObjcBuild`-[LGPerson idcard])
}
(lldb) p $5.get(4).big()
(method_t::big) $10 = {
name = "setIdcard:"
types = 0x0000000100003ec4 "v24@0:8@16"
imp = 0x0000000100003b60 (KCObjcBuild`-[LGPerson setIdcard:])
}
(lldb) p $5.get(5).big()
(method_t::big) $11 = {
name = "init"
types = 0x0000000100003e78 "@16@0:8"
imp = 0x00000001000039d0 (KCObjcBuild`-[LGPerson init])
}
(lldb) p $5.get(6).big()
(method_t::big) $12 = {
name = "name"
types = 0x0000000100003e78 "@16@0:8"
imp = 0x0000000100003a40 (KCObjcBuild`-[LGPerson name])
}
(lldb) p $5.get(7).big()
(method_t::big) $13 = {
name = "setName:"
types = 0x0000000100003ec4 "v24@0:8@16"
imp = 0x0000000100003a70 (KCObjcBuild`-[LGPerson setName:])
}
(lldb) p $5.get(8).big()
(method_t::big) $14 = {
name = "desc"
types = 0x0000000100003e78 "@16@0:8"
imp = 0x0000000100003b00 (KCObjcBuild`-[LGPerson desc])
}
(lldb) p $5.get(9).big()
(method_t::big) $15 = {
name = "setDesc:"
types = 0x0000000100003ec4 "v24@0:8@16"
imp = 0x0000000100003b20 (KCObjcBuild`-[LGPerson setDesc:])
}
3.获取协议方法
(lldb) p/x LGPerson.class
(Class) $0 = 0x00000001000089d8 LGPerson
(lldb) p (class_data_bits_t *)0x00000001000089f8
(class_data_bits_t *) $1 = 0x00000001000089f8
(lldb) p $1->data()
(class_rw_t *) $2 = 0x000000010064eb80
(lldb) p $2.protocols()
(const protocol_array_t) $3 = {
list_array_tt<unsigned long, protocol_list_t, RawPtr> = {
= {
list = {
ptr = 0x00000001000082f0
}
arrayAndFlag = 4295000816
}
}
}
Fix-it applied, fixed expression was:
$2->protocols()
(lldb) p $3.list.ptr
(protocol_list_t *const) $4 = 0x00000001000082f0
(lldb) p $4.list[0]
(protocol_ref_t) $5 = 4295002672
Fix-it applied, fixed expression was:
$4->list[0]
(lldb) p (protocol_t *)$5
(protocol_t *) $6 = 0x0000000100008a30
(lldb) p * $6
(protocol_t) $7 = {
objc_object = {
isa = {
bits = 4298547400
cls = Protocol
= {
nonpointer = 0
has_assoc = 0
has_cxx_dtor = 0
shiftcls = 537318425
magic = 0
weakly_referenced = 0
unused = 0
has_sidetable_rc = 0
extra_rc = 0
}
}
}
mangledName = 0x0000000100003c0a "proDelegate"
protocols = 0x0000000100008488
instanceMethods = 0x00000001000084a0
classMethods = 0x0000000100008520
optionalInstanceMethods = nil
optionalClassMethods = nil
instanceProperties = 0x0000000100008540
size = 96
flags = 0
_extendedMethodTypes = 0x0000000100008568
_demangledName = 0x0000000000000000
_classProperties = nil
}
(lldb) p $7.instanceMethods //实例方法
(method_list_t *) $8 = 0x00000001000084a0
(lldb) p $8.get(0).big()
(method_t::big) $9 = {
name = "aaaTest:"
types = 0x0000000100003edb "v24@0:8@16"
imp = 0x0000000000000000
}
Fix-it applied, fixed expression was:
$8->get(0).big()
(lldb) p $8.get(1).big()
(method_t::big) $10 = {
name = "name"
types = 0x0000000100003e6a "@16@0:8"
imp = 0x0000000000000000
}
Fix-it applied, fixed expression was:
$8->get(1).big()
(lldb) p $8.get(2).big()
(method_t::big) $11 = {
name = "setName:"
types = 0x0000000100003edb "v24@0:8@16"
imp = 0x0000000000000000
}
Fix-it applied, fixed expression was:
$8->get(2).big()
(lldb) p $8.get(3).big()
(method_t::big) $12 = {
name = "age"
types = 0x0000000100003ec8 "i16@0:8"
imp = 0x0000000000000000
}
Fix-it applied, fixed expression was:
$8->get(3).big()
(lldb) p $8.get(4).big()
(method_t::big) $13 = {
name = "setAge:"
types = 0x0000000100003ed0 "v20@0:8i16"
imp = 0x0000000000000000
}
Fix-it applied, fixed expression was:
$8->get(4).big()
(lldb) p $7.classMethods //类方法
(method_list_t *) $14 = 0x0000000100008520
(lldb) p $14.get(0).big()
(method_t::big) $15 = {
name = "aaaTest:"
types = 0x0000000100003edb "v24@0:8@16"
imp = 0x0000000000000000
}
Fix-it applied, fixed expression was:
$14->get(0).big()
(lldb) p $7.instanceProperties //属性
(property_list_t *) $16 = 0x0000000100008540
(lldb) p * $16
(property_list_t) $17 = {
entsize_list_tt<property_t, property_list_t, 0, PointerModifierNop> = (entsizeAndFlags = 16, count = 2)
}
(lldb) p $17.get(0)
(property_t) $18 = (name = "name", attributes = "T@\"NSString\",&,N")
(lldb) p $17.get(1)
(property_t) $19 = (name = "age", attributes = "Ti,N")
(lldb) p $17.get(2)