美文网首页codeER.teciOS收藏
iOS底层-类的底层原理(一)

iOS底层-类的底层原理(一)

作者: 沉淀纷飞 | 来源:发表于2021-06-17 18:02 被阅读0次

    案例分析


    1、通过终端cd 到main.m文件所在目录
    2、终端输入xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main64.cpp 编译会得到一个c++文件(具体问什么这么做呢,可参考iOS底层-对象的本质

    查看编译后的文件,我们可以得出实例对象实质为结构体,该结构体包含类指针和成员变量。

    从图中可以看出NSObject也是objc_object类型的结构体,其内部一样包含isa指针和其他成员变量。在内存中isa地址就是instance的地址,其他成员变量依次排在后面。

    打印结果如下

    从打印结果中可以发现class1和class2的地址一样,class3、class4和class5的地址一样。
    通过苹果官网下载objc源码,从源码中我们可以找到Class的源码实现。

    我们可以得出结论Classobjc_class的结构体指针。那么objc_classobjc_object的内部是怎么实现的呢?
    struct objc_class : objc_object {
      objc_class(const objc_class&) = delete;
      objc_class(objc_class&&) = delete;
      void operator=(const objc_class&) = delete;
      void operator=(objc_class&&) = delete;
        // 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
        ...代码太长省略
    
    struct objc_object {
    private:
        isa_t isa;
    
    public:
    
        // ISA() assumes this is NOT a tagged pointer object
        Class ISA(bool authenticated = false);
    
        // rawISA() assumes this is NOT a tagged pointer object or a non pointer ISA
        Class rawISA();
    
        // getIsa() allows this to be a tagged pointer object
        Class getIsa();
        
        uintptr_t isaBits() const;
        ...代码太长省略
    

    从源码从可以看到类中class_rw_t存储了变量、方法列表、协议列表、版本等信息。

    struct class_rw_t {
        // Be warned that Symbolication knows the layout of this structure.
        uint32_t flags;
        uint16_t witness;
    #if SUPPORT_INDEXED_ISA
        uint16_t index;
    #endif
    
        explicit_atomic<uintptr_t> ro_or_rw_ext;
    
        Class firstSubclass;
        Class nextSiblingClass;
    
    private:
        // 部分代码已省略
        // 方法列表
        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 *>(&ro_or_rw_ext)->methods;
            } else {
                return method_array_t{v.get<const class_ro_t *>(&ro_or_rw_ext)->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 *>(&ro_or_rw_ext)->properties;
            } else {
                return property_array_t{v.get<const class_ro_t *>(&ro_or_rw_ext)->baseProperties};
            }
        }
       //协议列表
        const protocol_array_t protocols() const {
            auto v = get_ro_or_rwe();
            if (v.is<class_rw_ext_t *>()) {
                return v.get<class_rw_ext_t *>(&ro_or_rw_ext)->protocols;
            } else {
                return protocol_array_t{v.get<const class_ro_t *>(&ro_or_rw_ext)->baseProtocols};
            }
        }
    };
    

    下面我们通过案例结合lldb分析类、元类和根元类


    我们可以得到类对象isa指向的类对象我们称之为`元类。实例方法存储在类对象中,类方法存储在元类对象中。对象、类、元类我们一般通过下面的关系图说明

    由图可见元类的isa 指向基类的元类。基类的元类的 superclass 指向基类

    总结

    • 类的本质是对象
    • 类对象是一种数据结构,类存储的基本信息包含类大小、名称、版本、继承层次和消息与函数的映射表
    • 对象方法存放在类里面
    • 类方法存放在元类里面
    • 成员变量存放在class_ro_t中的ivar_list_t
    • 属性在class_rw_t中的property_array_tclass_ro_t中的的property_list_t都存着一份,并且会生成实例变量,和对应的方法
    • 方法在class_rw_t中的method_array_tclass_ro_t中的的method_list_t都存着一份
    • instance对象的isa指向Class对象
    • Class对象的isa指向meta-class对象
    • meta-class对象的isa指向基类的meta-class对象

    相关文章

      网友评论

        本文标题:iOS底层-类的底层原理(一)

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