iOS-底层原理 03 对象的本质 & isa

·  阅读 217
iOS-底层原理 03 对象的本质 & isa

根据clangobj.h查看对象创建的流程和方法

Clang介绍

clang是一个由Apple主导编写,基于LLVMC/C++/OC的编译器
主要是用于底层编译,将一些文件输出成c++文件,例如main.m 输出成main.cpp,其目的是为了更好的观察底层的一些结构实现的逻辑,方便理解底层原理

对象的本质

1.使用clang把OC对象编译成C++,查看底层代码。可以使用如下代码在控制台中编译指定类:

clang -rewrite-objc main.m -o main.cpp 
//UIKit报错
clang -x objective-c -rewrite-objc -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk main.m
// xcrun命令基于clang基础上进行了封装更好用
//3、模拟器编译
 xcrun -sdk iphonesimulator clang -arch arm64 -rewrite-objc main.m -o main-arm64.cpp 
//4、真机编译
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main- arm64.cpp 
复制代码

2.我使用了如下代码编译了HTPerson.m 类,在同一目录下生成了HTPerson.cpp文件,点击查看

clang -rewrite-objc HTPerson.m -o HTPerson.cpp
复制代码

3.搜索HTPerson 看到如下代码

extern "C" unsigned long OBJC_IVAR_$_HTPerson$_HTName;
struct HTPerson_IMPL {
	struct NSObject_IMPL NSObject_IVARS;
	NSString * _Nonnull _HTName;
};
复制代码

可以看出NSObject底层是结构体,同时多了一个成员ivars

4.搜索类型NSObject_IMPL发现ivars中只有一个isa

struct NSObject_IMPL {
	Class isa;
};
复制代码

5.再次搜索*Class

typedef struct objc_class *Class;


struct objc_object {
    Class _Nonnull isa __attribute__((deprecated));
};


typedef struct objc_object *id;


typedef struct objc_selector *SEL;
复制代码

发现class实际上是一个objc_class类型的结构体指针。同时isa应该包含类的相关信息。

探索isa

查看OC的底层源码发现,在对象创建时(alloc方法可以查看)有三个步骤:
1.cls->instanceSize 计算内存大小
2.开辟内存并且返回地址指针
3.isa会关联内存对象的类。

isa关联对象和内存的方法

objc_object::initIsa(Class cls, bool nonpointer, bool hasCxxDtor) 
{ 
    ASSERT(!isTaggedPointer()); 
    
    if (!nonpointer) {
        isa = isa_t((uintptr_t)cls);
    } else {
        ASSERT(!DisableNonpointerIsa);
        ASSERT(!cls->instancesRequireRawIsa());
        
        isa_t newisa(0);
#if SUPPORT_INDEXED_ISA
        ASSERT(cls->classArrayIndex() > 0);
        newisa.bits = ISA_INDEX_MAGIC_VALUE;
        newisa.has_cxx_dtor = hasCxxDtor;
        newisa.indexcls = (uintptr_t)cls->classArrayIndex();
#else
        newisa.bits = ISA_MAGIC_VALUE;
        newisa.has_cxx_dtor = hasCxxDtor;
        newisa.shiftcls = (uintptr_t)cls >> 3;
#endif
        isa = newisa;
    }
}
复制代码

其中isa_t是一个联合体。联合体成员是互斥的 ,那就意味着初始化isa有两种方式:
bits被赋值,cls没有值或者被覆盖
cls 被赋值,bits没有值或者被覆盖
好处就是可以节约内存空间,总共占用了8字节 * 8位 = 64

isa_t的实现

union isa_t {
    isa_t() { }
    isa_t(uintptr_t value) : bits(value) { }

    Class cls;
    uintptr_t bits;
#if defined(ISA_BITFIELD)
    struct {
        ISA_BITFIELD;  // defined in isa.h
    };
#endif
};
复制代码

搜索ISA_BITFIELD,并且查看内容

# if __arm64__
#   define ISA_MASK        0x0000000ffffffff8ULL
#   define ISA_MAGIC_MASK  0x000003f000000001ULL
#   define ISA_MAGIC_VALUE 0x000001a000000001ULL
#   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 deallocating      : 1;                                       \
      uintptr_t has_sidetable_rc  : 1;                                       \
      uintptr_t extra_rc          : 19
#   define RC_ONE   (1ULL<<45)
#   define RC_HALF  (1ULL<<18)
复制代码

nonpointer:表示是否对 isa 指针开启指针优化0:纯isa指针,1:不⽌是类对象地址,isa 中包含了类信息、对象的引⽤计数等
has_assoc:关联对象标志位,0没有,1存在
has_cxx_dtor:该对象是否有 C++ 或者 Objc 的析构器,如果有析构函数,则需要做析构逻辑, 如果没有,则可以更快的释放对象
shiftcls: 存储类指针的值。开启指针优化的情况下,在 arm64 架构中有 33 位⽤来存储类指针。
magic:⽤于调试器判断当前对象是真的对象还是没有初始化的空间
weakly_referenced:对象是否被指向或者曾经指向⼀个 ARC 的弱变量,没有弱引⽤的对象可以更快释放。
deallocating:标志对象是否正在释放内存
has_sidetable_rc:当对象引⽤技术⼤于 10 时,则需要借⽤该变量存储进位
extra_rc:当表示该对象的引⽤计数值,实际上是引⽤计数值减 1。例如,如果对象的引⽤计数为 10,那么 extra_rc 为 9。如果引⽤计数⼤于 10, 则需要使⽤到下⾯的 has_sidetable_rc。

总结

对象其实指向一个结构体的指针。isa是联合体+位域的方式存储类的信息。采用这种方式的有点就是节省大量内存。

分类:
iOS
标签:
收藏成功!
已添加到「」, 点击更改