美文网首页
OC 类的结构分析

OC 类的结构分析

作者: 东旭39 | 来源:发表于2020-09-13 20:35 被阅读0次

    网络中有个关于类的关系的图


    isa流程图.png

    图中虚线部分是isa的的继承关系
    证明如下图


    image.png

    有关lldb指令的说明:

    • p/x 以16进制形式打印
    • x/4gx 读取内存地址,冒号左边为地址,冒号右边为地址存储的值
    • po 打印实现了description方法
    1. 对象->类
    //打印16进制person的内存地址
    (lldb) p/x person
    (LGPerson *) $26 = 0x00000001006e8400
    //读取person的内存地址
    (lldb) x/4gx 0x00000001006e8400
    0x1006e8400: 0x001d8001000020f1 0x0000000000000000
    0x1006e8410: 0x00000001006e84e0 0x00000001006e8720
    //isa指针与上ISA_MASK 0x00007ffffffffff8ULL得到类信息
    (lldb) p/x 0x001d8001000020f1 & 0x00007ffffffffff8ULL
    //得到类的信息
    (unsigned long long) $27 = 0x00000001000020f0
    (lldb) po 0x00000001000020f0
    LGPerson
    

    其中0x001d8001000020f1是类的isa指针,

    1. 类->元类
    //读取类的地址的内存
    (lldb) x/4gx 0x00000001000020f0
    0x1000020f0: 0x00000001000020c8 0x0000000100334140
    0x100002100: 0x000000010032e410 0x0000801000000000
    (lldb) p/x 0x00000001000020c8 & 0x00007ffffffffff8ULL
    //元类地址
    (unsigned long long) $29 = 0x00000001000020c8
    (lldb) po 0x00000001000020c8
    LGPerson
    

    其中0x00000001000020c8是元类的isa指针

    1. 元类->根元类
    //读取元类的内存地址
    (lldb) x/4gx 0x00000001000020c8
    0x1000020c8: 0x00000001003340f0 0x00000001003340f0
    0x1000020d8: 0x00000001006420f0 0x0004e03100000007
    (lldb) po 0x00000001003340f0
    NSObject
    

    其中0x00000001003340f0是根元类的isa指针

    1. 根元类->根元类
    (lldb) p/x 0x00000001003340f0 & 0x00007ffffffffff8ULL
    (unsigned long long) $32 = 0x00000001003340f0
    (lldb) x/4gx 0x00000001003340f0
    0x1003340f0: 0x00000001003340f0 0x0000000100334140
    0x100334100: 0x00000001006e6a50 0x0004e03100000007
    (lldb) po 0x00000001003340f0
    NSObject
    

    类的继承

    在objc-private.h中的objc_object是根对象

    struct objc_object {
    private:
        isa_t isa;
    public:
        // ISA() assumes this is NOT a tagged pointer object
        Class ISA();
        省略号
    };
    
    

    objc_class也是继承自objc_object

    struct objc_class : objc_object {
        // 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
        省略号
    }
    

    objc的源码地址
    所以objc_object是万物的根源。所有的类都是由它的模板创建而来。上层通过底层objc的提供的方法创建对象。

    类的结构

    源码在objc-runtime-new.h中

    struct objc_class : objc_object {
        // Class ISA;      isa指针8个字节
        Class superclass;        //父类8个字节
        cache_t cache;             // formerly cache pointer and vtable 16
        class_data_bits_t bits;    // class_rw_t * plus custom rr/alloc flags
        class_rw_t *data() const {
            return bits.data();
        }
        //省略号
      //下面的都是方法,方法不占用结构体内存
    }
    

    其中isa8个字节,父类superclass8个字节,cache占16个,根据c语言规范,要读取bits内容需要从objc_class的首地址开始偏移32位读取。
    创建类

    @interface LGPerson : NSObject
    
    @property(nonatomic,copy) NSString *nickName;
    @property(nonatomic,copy) NSString *identifer;
    
    -(void)sayHello;
    
    +(void)sayWorld;
    
    @end
    
    #import "LGPerson.h"
    
    @implementation LGPerson
    -(void)sayHello{
    }
    +(void)sayWorld{
    }
    @end
    
    
    image.png

    如图

    1. 获取类的首地址0x0000000100002248,objc_class是一个结构体,其中isa8个字节,父类superclass8个字节,cache占16个,要读取bits需要从类的首地址开始偏移32位读取。cache通过查看其源码得知是16位。
    2. 此时$1为bits,调用其data()方法,返回一个class_rw_t类型的数据$3,返回的数据信息不熟悉。查看class_rw_t源码有如下
        //方法
        const method_array_t methods() const {
            auto v = get_ro_or_rwe();
            if (v.is<class_rw_ext_t *>()) {
                return v.get<class_rw_ext_t *>()->methods;
            } else {
                return method_array_t{v.get<const class_ro_t *>()->baseMethods()};
            }
        }
        //属性
        const property_array_t properties() const {
            auto v = get_ro_or_rwe();
            if (v.is<class_rw_ext_t *>()) {
                return v.get<class_rw_ext_t *>()->properties;
            } else {
                return property_array_t{v.get<const class_ro_t *>()->baseProperties};
            }
        }
    
    
    1. 控制台打印class_rw_t的properties()方法
    (const property_array_t) $4 = {
      list_array_tt<property_t, property_list_t> = {
         = {
          list = 0x00000001000021d0
          arrayAndFlag = 4294975952
        }
      }
    }
    (lldb) p $4.list
    (property_list_t *const) $5 = 0x00000001000021d0
    (lldb) p *$5
    (property_list_t) $6 = {
      entsize_list_tt<property_t, property_list_t, 0> = {
        entsizeAndFlags = 16
        count = 2
        first = (name = "nickName", attributes = "T@\"NSString\",C,N,V_nickName")
      }
    }
    

    这个properties()方法可以获取我们在LGPerson中定义的属性如下图


    image.png

    同理,我们可以获取类中的methods


    image.png
    1. 调用class_rw_t ($3)的methods()方法,返回方法信息
    2. 读取list中的信息,发现有6个方法,
      • 在LGPerson中定义的方法sayHello
      • 属性nikName和identifier的get和set方法
      • .cxx_destruct方法
    3. 发现我们定义的类方法并不存在这个metho_list中。

    类方法

    类方法不在类中,那么根据第一张图,类方法是否在元类中


    image.png

    lldb断点查看LGPerson可以发现类方法存在与元类中
    class的结构初步分析如上

    相关文章

      网友评论

          本文标题:OC 类的结构分析

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