003-OC对象本质

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地址,还存储了对象的其他相关信息。
  • 联合体位域的使用,优化了内存也提高了部分信息的查询效率。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容