iOS

iOS-isa指向图&类结构(上)

2021-06-19  本文已影响0人  Summit_yp

一.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 & superclass 的指向图

相信这个时候来看就清晰了许多,那么怎么验证图中实例对象isa的走向呢?

main.m中添加如下代码:

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        YPPerson *instancePerson = [YPPerson alloc];
        YPTeacher *instanceTeacher = [YPTeacher alloc];
        NSLog(@"%@,%@",instancePerson,instanceTeacher);
    }
    return 0;
}

打下断点并运行:

image.png
使用lldb调试:
image.png
拿到isa&ISA_MASK就得到isa的真实指向,即YPPerson
image.png
同理得到YPTeacher

类的结构的探究

已知类在底层是object_class的结构体,直接在源码中搜索object_class,关键源码如下:

image.png

可以知道,类中有以下变量:

    // 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继承而来

image.png

其每个变量的大小如下,ISAsuperclass都是结构体指针为8字节,cache的大小为16字节

    // Class ISA;                   // 8字节
    Class superclass;         // 8字节
    cache_t cache;             // 16字节
    class_data_bits_t bits;    

那么类的相关信息例如属性,方法列表都存在那里呢?

直接开启上帝视角,答案是存在 bits中,我们来看看bit的结构吧。

class_data_bits_t结构
直接定位到data()方法,看看class_rw_t中都有些什么呢?
class_rw_t结构
诶嘿,找到methods() properties() protocols()啦。接下来我们用lldb调试,验证一下吧。

YPPerson添加一些属性,方法

@interface YPPerson : NSObject
{
    NSString *name;
}
@property (copy,nonatomic)NSString *yp_name;
- (void)handsomYP;
+ (void)beautifulWife;

@end

打上断点,运行源码。


image.png image.png image.png

属性同理,一步步走进去就可以看见啦。那么问题来了,- (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<unsigned long> = {
      Value = 4302785969
    }
  }
  firstSubclass = nil
  nextSiblingClass = 0x00007fff90831cd8
}
(lldb) p $20.methods()
(const method_array_t) $21 = {
  list_array_tt<method_t, method_list_t, method_list_t_authed_ptr> = {
     = {
      list = {
        ptr = 0x0000000100008080
      }
      arrayAndFlag = 4295000192
    }
  }
}
(lldb) p $21.list
(const method_list_t_authed_ptr<method_list_t>) $22 = {
  ptr = 0x0000000100008080
}
(lldb) p $22.ptr
(method_list_t *const) $23 = 0x0000000100008080
(lldb) p *$23
(method_list_t) $24 = {
  entsize_list_tt<method_t, method_list_t, 4294901763, method_t::pointer_modifier> = (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,😁😁😁

上一篇下一篇

猜你喜欢

热点阅读