一.isa
& superclass
的指向探究
靓仔们,我们在main.m
中添加如下代码:
@interface YPPerson : NSObject
@end
@implementation YPPerson
@end
@interface YPTeacher : YPPerson
@end
@implementation YPTeacher
@end
在iOS-对象的本质,ISA分析中提到了clang,这里我们仍然使用clang -rewrite-objc main.m -o main.cpp
编译main.m
文件,打开main.cpp
,搜索YPPerson
,得到如下结果:
static void OBJC_CLASS_SETUP_$_YPPerson(void ) {
//YPPerson的元类的isa指向NSObject的元类,也就是根元类
OBJC_METACLASS_$_YPPerson.isa = &OBJC_METACLASS_$_NSObject;
//YPPerson的元类的父类指向NSObject的元类,也就是根元类
OBJC_METACLASS_$_YPPerson.superclass = &OBJC_METACLASS_$_NSObject;
OBJC_METACLASS_$_YPPerson.cache = &_objc_empty_cache;
//YPPerson类对象的isa指向YPPerson的元类
OBJC_CLASS_$_YPPerson.isa = &OBJC_METACLASS_$_YPPerson;
//YPPerson类对象的父类指向NSObject的类对象
OBJC_CLASS_$_YPPerson.superclass = &OBJC_CLASS_$_NSObject;
OBJC_CLASS_$_YPPerson.cache = &_objc_empty_cache;
}
搜索YPTeacher,得到如下关键信息:
static void OBJC_CLASS_SETUP_$_YPTeacher(void ) {
//YPTeacher的元类的isa指向NSObject的元类,也就是根元类
OBJC_METACLASS_$_YPTeacher.isa = &OBJC_METACLASS_$_NSObject;
//YPTeacher的元类的父类指向YPPerson的元类
OBJC_METACLASS_$_YPTeacher.superclass = &OBJC_METACLASS_$_YPPerson;
OBJC_METACLASS_$_YPTeacher.cache = &_objc_empty_cache;
//YPTeacher类对象的isa指向YPTeacher的元类
OBJC_CLASS_$_YPTeacher.isa = &OBJC_METACLASS_$_YPTeacher;
//YPTeacher类对象的父类指向YPPerson的类对象
OBJC_CLASS_$_YPTeacher.superclass = &OBJC_CLASS_$_YPPerson;
OBJC_CLASS_$_YPTeacher.cache = &_objc_empty_cache;
}
oh my gad! 这也太直观了吧,接下来有请我们著名的isa走向图,将其与我们的例子相结合:
相信这个时候来看就清晰了许多,那么怎么验证图中实例对象isa的走向呢?
在main.m
中添加如下代码:
int main(int argc, const char * argv[]) {
@autoreleasepool {
YPPerson *instancePerson = [YPPerson alloc];
YPTeacher *instanceTeacher = [YPTeacher alloc];
NSLog(@"%@,%@",instancePerson,instanceTeacher);
}
return 0;
}
打下断点并运行:
使用lldb调试:
拿到
isa
,&
上ISA_MASK
就得到isa的真实指向,即YPPerson
。
同理得到
YPTeacher
。
类的结构的探究
已知类在底层是object_class
的结构体,直接在源码中搜索object_class
,关键源码如下:
可以知道,类中有以下变量:
// 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
为什么ISA
被注释掉了呢?因为这个是由objc_object
继承而来
其每个变量的大小如下,ISA
和 superclass
都是结构体指针为8字节,cache
的大小为16字节
// Class ISA; // 8字节
Class superclass; // 8字节
cache_t cache; // 16字节
class_data_bits_t bits;
那么类的相关信息例如属性,方法列表都存在那里呢?
直接开启上帝视角,答案是存在 bits
中,我们来看看bit的结构吧。
直接定位到
data()
方法,看看class_rw_t
中都有些什么呢?
诶嘿,找到
methods()
properties()
protocols()
啦。接下来我们用lldb调试,验证一下吧。
给YPPerson
添加一些属性,方法
@interface YPPerson : NSObject
{
NSString *name;
}
@property (copy,nonatomic)NSString *yp_name;
- (void)handsomYP;
+ (void)beautifulWife;
@end
打上断点,运行源码。
属性同理,一步步走进去就可以看见啦。那么问题来了,- (void)handsomYP
帅气我们有了,+ (void)beautifulWife
这个漂亮老婆跑哪去了呢?
(lldb) x/4gx YPPerson.class
0x1000087c0: 0x0000000100008798 0x0000000100357140
0x1000087d0: 0x0000000100352360 0x0000802000000000
(lldb) p/x 0x0000000100008798 & 0x00007ffffffffff8ULL//isa&isa_mask
(unsigned long long) $16 = 0x0000000100008798//元类的地址
(lldb) po 0x0000000100008798 & 0x00007ffffffffff8ULL
YPPerson//元类
//后续就跟上一步获取方法列表一样啦
(lldb) x/4gx 0x0000000100008798
0x100008798: 0x00000001003570f0 0x00000001003570f0
0x1000087a8: 0x00000001019048d0 0x0002e03100000003
(lldb) p (class_data_bits_t *)0x1000087b8
(class_data_bits_t *) $18 = 0x00000001000087b8
(lldb) p $18->data()
(class_rw_t *) $19 = 0x0000000100774810
(lldb) p *$19
(class_rw_t) $20 = {
flags = 2684878849
witness = 1
ro_or_rw_ext = {
std::__1::atomic = {
Value = 4302785969
}
}
firstSubclass = nil
nextSiblingClass = 0x00007fff90831cd8
}
(lldb) p $20.methods()
(const method_array_t) $21 = {
list_array_tt = {
= {
list = {
ptr = 0x0000000100008080
}
arrayAndFlag = 4295000192
}
}
}
(lldb) p $21.list
(const method_list_t_authed_ptr) $22 = {
ptr = 0x0000000100008080
}
(lldb) p $22.ptr
(method_list_t *const) $23 = 0x0000000100008080
(lldb) p *$23
(method_list_t) $24 = {
entsize_list_tt = (entsizeAndFlags = 27, count = 1)
}
(lldb) p $24.get(0).big()
(method_t::big) $25 = {
name = "beautifulWife"
types = 0x0000000100003e24 "v16@0:8"
imp = 0x0000000100003810 (KCObjcBuild`+[YPPerson beautifulWife] at main.m:51)
}
由此可知,beautifulWife在元类的方法列表里去啦,终于找到漂亮老婆了,嘿嘿。
看我帖子的都能找到beautifulWife,