iOS底层 - 对象的本质&isa分析

2021-07-16  本文已影响0人  degulade

前言

OC是一个面向对象的编程语言,对象就是我们整个编写代码的过程中,最为频繁接触到的一个东西,那么什么是对象呢?在上一篇文章iOS底层 - 结构体内存对齐中,我们了解到:对象的本质就是结构体。那么这个结论怎么验证呢?那么下面开始一探究竟。

一.了解clang

在探究对象本质之前先介绍一下clang:

二.编译oc文件为c++文件

  1. 直接命令行编译 :
//  把⽬标⽂件编译成c+
clang -rewrite-objc main.m -o main.cpp 
  1. xcode安装的时候顺带安装了xcrun命令,xcrun命令在clang的基础上进⾏了⼀些封装,要更好⽤⼀些:
//  模拟器
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 
  1. 成功生成如下文件:


三.分析c++文件

开发main.cpp文件,搜索LGPerson

LGPerson
上图所示,我们可以看到对象在底层的本质是一个结构体。

跟踪NSObject_IMPL结构类型可以看到如图下:


isa objc

上图所示,可以得出objc底层调用就是objc_object

@property (nonatomic, strong) NSString *KCName;
// @implementation LGPerson
// 方法 getter
static NSString * _I_LGPerson_kcName(LGPerson * self, SEL _cmd) {
    return (*(NSString **)((char *)self + OBJC_IVAR_$_LGPerson$_kcName))
}

static void _I_LGPerson_setKcName_(LGPerson * self, SEL _cmd, NSString *kcName) { (*(NSString **)((char *)self + OBJC_IVAR_$_LGPerson$_kcName)) = kcName; }
// @end

四.isa分析

struct NSObject_IMPL {
    Class isa;
};

在上面的代码里,我们可以看到NSObject里面只有一个成员变量,那就是Class类型的isa。那么这isa是什么呢,我们就这个问题,继续探索下去,首先我们先看看他的类型Class在底层中的定义。

typedef struct objc_class *Class;

struct objc_class {
    Class _Nonnull isa  OBJC_ISA_AVAILABILITY;

#if !__OBJC2__
    Class _Nullable super_class                              OBJC2_UNAVAILABLE;
    const char * _Nonnull name                               OBJC2_UNAVAILABLE;
    long version                                             OBJC2_UNAVAILABLE;
    long info                                                OBJC2_UNAVAILABLE;
    long instance_size                                       OBJC2_UNAVAILABLE;
    struct objc_ivar_list * _Nullable ivars                  OBJC2_UNAVAILABLE;
    struct objc_method_list * _Nullable * _Nullable methodLists                    OBJC2_UNAVAILABLE;
    struct objc_cache * _Nonnull cache                       OBJC2_UNAVAILABLE;
    struct objc_protocol_list * _Nullable protocols          OBJC2_UNAVAILABLE;
#endif

} OBJC2_UNAVAILABLE;

可以看到,Class实际上就是一个objc_class *类型的结构体指针。

接下来我们来看看isa,在alloc流程的最后一步,就是通过initIsa方法将我们申请的内存地址和我们的Class绑定起来。

inline void 
objc_object::initIsa(Class cls, bool nonpointer, UNUSED_WITHOUT_INDEXED_ISA_AND_DTOR_BIT bool hasCxxDtor)
{ 
    ASSERT(!isTaggedPointer()); 
    
    isa_t newisa(0);
    if (!nonpointer) {
        newisa.setClass(cls, this);
    } else {
        ASSERT(!DisableNonpointerIsa);
        ASSERT(!cls->instancesRequireRawIsa());
#if SUPPORT_INDEXED_ISA
        ASSERT(cls->classArrayIndex() > 0);
        newisa.bits = ISA_INDEX_MAGIC_VALUE;
        // isa.magic is part of ISA_MAGIC_VALUE
        // isa.nonpointer is part of ISA_MAGIC_VALUE
        newisa.has_cxx_dtor = hasCxxDtor;
        newisa.indexcls = (uintptr_t)cls->classArrayIndex();
#else
        newisa.bits = ISA_MAGIC_VALUE;
        // isa.magic is part of ISA_MAGIC_VALUE
        // isa.nonpointer is part of ISA_MAGIC_VALUE
#   if ISA_HAS_CXX_DTOR_BIT
        newisa.has_cxx_dtor = hasCxxDtor;
#   endif
        newisa.setClass(cls, this);
#endif
        newisa.extra_rc = 1;
    }
    isa = newisa;
}

在这些代码中间,有个非常重要的东西,就是isa_t,我们再来看看它到底是什么:

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);
};

五.结构体和联合体

在上面的代码中,我们可以看到一个之前没有接触过的结构union,我们称之为联合体,那么他到底是什么,有什么特性呢,我们用下面这个例子来说明,首先看一段代码

// 结构体 : 共存
struct XHTeacher1 {
    char        *name;
    int         age;
    double      height ;
};

// 联合体 : 互斥
union XHTeacher2 {
    char        *name;
    int         age;
    double      height ;
};
上一篇 下一篇

猜你喜欢

热点阅读