美文网首页
003-OC对象本质

003-OC对象本质

作者: 可可先生_3083 | 来源:发表于2021-07-20 00:46 被阅读0次

    oc是面向对象的语言。对象可以看做我们对底层数据的抽象封装。对象有自己的成员变量,具备一些功能,有自己所属的类,甚至有父类,子类。那么oc的面相对象是怎么设计,怎么实现的?它的底层是由什么样的数据结构支持的呢?

    编译

    把OC编译成c/c++是我们了解OC底层实现的一种方式。
    简单的clang编译

    clang -rewrite-objc main.m -o main.cpp 
    

    有时候clang编译会需要一些环境,sdk支持,动态特性支持

    clang -rewrite-objc -fobjc-arc -fobjc-runtime=ios-13.0.0 -isysroot /
    Applications/Xcode.app/Contents/Developer/Platforms/
    iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator13.0.sdk main.m
    

    xcrun命令 xcode自带的命令行工具,在clang基础上进行了一些封装,编译oc代码,更简便一些

    xcrun -sdk iphonesimulator clang -arch arm64 -rewrite-objc main.m -o 
    main-arm64.cpp (模拟器)
    
    xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main�arm64.cpp (⼿机)
    

    gcc编译器在xcode的早期版本中使用,xcode现在的编译器是LLVM,采用三项插拔式设计。LLVM设计的最重要方面是,使用通用代码表示形式(IR),它是用来在编译器中表示代码的形式。所以LLVM可以以任何编程语言独立编写前端,并且可以为任意硬件架构独立编写后端。
    clang 是LLVM一个子项目。负责编译c/c++/Objective-c。

    cpp文件中的对象

    LGPerson
    typedef struct objc_object LGPerson;
    typedef struct {} _objc_exc_LGPerson;
    #endif
    
    struct LGPerson_IMPL {
        struct NSObject_IMPL NSObject_IVARS;
        NSString *hobby;
    };
    

    本质是一个objc_object类型的结构体。

    objc_object
    struct objc_object {
       Class _Nonnull isa  OBJC_ISA_AVAILABILITY;
    };
    
    Class
    typedef struct objc_class *Class;
    
    objc_class
    objc_class : objc_object {---}
    
    id
    typedef struct objc_object *id;
    

    根据已有信息画个图

    截屏2021-07-20 上午12.08.11.png

    总结下已有信息

    • 对象本质是一个objc_object类型的结构体
    • 对象都有一个指向objc_class结构体的指针isa
    • objc_class结构体也有一个指向objc_class的指针isa
    • id类型是objc_object *

    难道我们isa指向会无限循环下吗,如果不会那对象objc_object 和objc_class他们之间的结构是怎么样的呢?
    无论如何,我们可以看到isa指针在期中扮演这关键的角色

    isa

    objc源码

    union isa_t {
        isa_t() { }
        isa_t(uintptr_t value) : bits(value) { }
    
        uintptr_t bits;
    
    private:
        // Accessing the class requires custom ptrauth operations, so
        // force clients to go through setClass/getClass by making this
        // private.
        Class cls;
    
    public:
    #if defined(ISA_BITFIELD)
        struct {
            ISA_BITFIELD;  // defined in isa.h
        };
    
        bool isDeallocating() {
            return extra_rc == 0 && has_sidetable_rc == 0;
        }
        void setDeallocating() {
            extra_rc = 0;
            has_sidetable_rc = 0;
        }
    #endif
    
        void setClass(Class cls, objc_object *obj);
        Class getClass(bool authenticated);
        Class getDecodedClass(bool authenticated);
    };
    

    如果是64位系统,isa_t是联合体位域,现在iOS手机基本都是arm64架构。
    ISA_BITFIELD是对位域的定义

    x86_64
    # elif __x86_64__
    #   define ISA_MASK        0x00007ffffffffff8ULL
    #   define ISA_MAGIC_MASK  0x001f800000000001ULL
    #   define ISA_MAGIC_VALUE 0x001d800000000001ULL
    #   define ISA_HAS_CXX_DTOR_BIT 1
    #   define ISA_BITFIELD                                                        \
          uintptr_t nonpointer        : 1;              //是否是nonpointer                           \
          uintptr_t has_assoc         : 1;    //是否有关联对象                                     \
          uintptr_t has_cxx_dtor      : 1;     //是否有cxx析构函数                                    \
          uintptr_t shiftcls          : 44; /*MACH_VM_MAX_ADDRESS 0x7fffffe00000*/ \
          uintptr_t magic             : 6;       //是否已完成初始化                                  \
          uintptr_t weakly_referenced : 1;  //是否被弱引用                                       \
          uintptr_t unused            : 1;           //是否正在被释放                              \
          uintptr_t has_sidetable_rc  : 1;     //引用计数是否存在sideTable中                                    \
          uintptr_t extra_rc          : 8    //存储该对象的引用计数值减一后的结果, 如果够存则存在这里,不够则存在 sidetable
    
    arm64
    # if __arm64__
    // ARM64 simulators have a larger address space, so use the ARM64e
    // scheme even when simulators build for ARM64-not-e.
    #   if __has_feature(ptrauth_calls) || TARGET_OS_SIMULATOR
    #     define ISA_MASK        0x007ffffffffffff8ULL
    #     define ISA_MAGIC_MASK  0x0000000000000001ULL
    #     define ISA_MAGIC_VALUE 0x0000000000000001ULL
    #     define ISA_HAS_CXX_DTOR_BIT 0
    #     define ISA_BITFIELD                                                      \
            uintptr_t nonpointer        : 1;                                       \
            uintptr_t has_assoc         : 1;                                       \
            uintptr_t weakly_referenced : 1;                                       \
            uintptr_t shiftcls_and_sig  : 52;                                      \
            uintptr_t has_sidetable_rc  : 1;                                       \
            uintptr_t extra_rc          : 8
    #     define RC_ONE   (1ULL<<56)
    #     define RC_HALF  (1ULL<<7)
    #   else
    #     define ISA_MASK        0x0000000ffffffff8ULL
    #     define ISA_MAGIC_MASK  0x000003f000000001ULL
    #     define ISA_MAGIC_VALUE 0x000001a000000001ULL
    #     define ISA_HAS_CXX_DTOR_BIT 1
    #     define ISA_BITFIELD                                                      \
            uintptr_t nonpointer        : 1;                                       \
            uintptr_t has_assoc         : 1;                                       \
            uintptr_t has_cxx_dtor      : 1;                                       \
            uintptr_t shiftcls          : 33; /*MACH_VM_MAX_ADDRESS 0x1000000000*/ \
            uintptr_t magic             : 6;         //                              \
            uintptr_t weakly_referenced : 1;                                       \
            uintptr_t unused            : 1;                                       \
            uintptr_t has_sidetable_rc  : 1;                                       \
            uintptr_t extra_rc          : 19
    #     define RC_ONE   (1ULL<<45)
    #     define RC_HALF  (1ULL<<18)
    

    位域提供了一种手段,使得可在高级语言中实现数据的压缩,节省了存储空间,同时也提高了程序的效率。

    上面我们isa是一个objc_class的指针。位域是我们充分利用了指针64位的内存空间,不进存储了objc_class的指着地址,还存楚了其他对象的相关信息。

    总结:

    • 对象本质是一个objc_object类型的结构体
    • 对象都有一个指向objc_class结构体的指针isa
    • objc_class结构体也有一个指向objc_class的指针isa
    • id类型是objc_object *
    • isa是一个联合体位域,不仅存储了objc_class地址,还存储了对象的其他相关信息。
    • 联合体位域的使用,优化了内存也提高了部分信息的查询效率。

    相关文章

      网友评论

          本文标题:003-OC对象本质

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