美文网首页iOS
iOS-isa指向图&类结构(上)

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

作者: Summit_yp | 来源:发表于2021-06-19 23:34 被阅读0次

    一.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,😁😁😁

    相关文章

      网友评论

        本文标题:iOS-isa指向图&类结构(上)

        本文链接:https://www.haomeiwen.com/subject/ruokyltx.html