OC底层

OC isa分析

2020-09-15  本文已影响0人  H丶ym

OC底层原理学习

这一章我们来探索一下alloc 源码核心中的
obj->initInstanceIsa(cls, hasCxxDtor) :将类与isa指针关联
step1:来到objc-object.h 中的initInstanceIsa的源码中

inline void 
objc_object::initInstanceIsa(Class cls, bool hasCxxDtor)
{
    ASSERT(!cls->instancesRequireRawIsa());
    ASSERT(hasCxxDtor == cls->hasCxxDtor());

    initIsa(cls, true, hasCxxDtor);
}

step2:来到objc-object.h中的initIsa的源码中

inline void 
objc_object::initIsa(Class cls, bool nonpointer, bool hasCxxDtor) 
{ 
    ASSERT(!isTaggedPointer()); 
    
    if (!nonpointer) {
        isa = isa_t((uintptr_t)cls); //isa 初始化
    } else {
        ASSERT(!DisableNonpointerIsa);
        ASSERT(!cls->instancesRequireRawIsa());

        isa_t newisa(0);//isa 初始化

#if SUPPORT_INDEXED_ISA // 通过cls初始化
        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 // 通过bits初始化
        newisa.bits = ISA_MAGIC_VALUE;
        // isa.magic is part of ISA_MAGIC_VALUE
        // isa.nonpointer is part of ISA_MAGIC_VALUE
        newisa.has_cxx_dtor = hasCxxDtor;
        //shiftcls 从第三位开始
        newisa.shiftcls = (uintptr_t)cls >> 3;
#endif

        // This write must be performed in a single store in some cases
        // (for example when realizing a class because other threads
        // may simultaneously try to use the class).
        // fixme use atomics here to guarantee single-store and to
        // guarantee memory order w.r.t. the class index table
        // ...but not too atomic because we don't want to hurt instantiation
        isa = newisa;
    }
}

我们可以看到isaisa_t类型的
来到objc-private.hisa_t的源码

//联合体
union isa_t {
    isa_t() { }
    isa_t(uintptr_t value) : bits(value) { }
    //提供了cls 和 bits ,两者是互斥关系
    Class cls;
    uintptr_t bits;
#if defined(ISA_BITFIELD)
    struct {
        ISA_BITFIELD;  // defined in isa.h
    };
#endif
};

联合体
联合体也是由不同的数据类型组成,但其变量是互斥的,所有的成员共占一段内存。而且共用体采用了内存覆盖技术,同一时刻只能保存一个成员的值,如果对新的成员赋值,就会将原来成员的值覆盖掉

与结构体的区别
结构体的各个成员会占用不同的内存,互相之间没有影响
共用体的所有成员占用同一段内存,修改一个成员会影响其余所有成员
结构体内存 >= 所有成员占用的内存总和(成员之间可能会有缝隙)
共用体占用的内存等于最大的成员占用的内存

isa_t是一个union联合体

__arm64__iOS(真机)
__ax86_64__macOS(模拟器)
uintptr_t nonpointer:是否对isa指针开启指针优化
uintptr_t has_assoc:关联对象标志位
uintptr_t has_cxx_dtor:表示该对象是否有C++/OC的析构器
uintptr_t shiftcls:存储类的指针的值(类的地址),真机占33位/模拟器占44位
uintptr_t magic:调试器判断对象是真对象还是未初始化空间
uintptr_t weakly_referenced:对象是否被指向或者曾经指向一个ARC的若变量
uintptr_t deallocating:标志对象是否正在释放内存
uintptr_t has_sidetable_rc:当对象引用计数大于10时,则需要借用该变量存储进位。
uintptr_t extra_rc:表示该对象的引用计数值,实际上是引用计数值减1,例如,如果对象的引用计数为10,那么extra_rc为9,如果大于10,就需要用到上面的has_sidetable_rc真机占19位/模拟器占8位

bits位域分布

initIsa源码分析
运行objc4-781源码,来到initIsa方法,添加断点,

step1 在初始化后打印newisa

isa初始值

step2bits赋值ISA_MAGIC_VALUE
ISA_MAGIC_VALUE宏源码
define ISA_MAGIC_VALUE 0x001d800000000001ULL
打印newisa

bits赋值

bits赋值后,magic = 59,59的二进制 0x001d800000000001ULL

step3 shiftcls赋值(uintptr_t)cls >> 3

shiftcls 赋值
shiftcls赋值后,cls也有值了

isa指针的应用

平时开发过程中,我们是通过object_getClass获取类名称
看下这个方法的源码
来到objc-class.mm

Class object_getClass(id obj)
{
    if (obj) return obj->getIsa();
    else return Nil;
}

来到objc-object.h中的getIsa

inline Class 
objc_object::getIsa() 
{
    if (fastpath(!isTaggedPointer())) return ISA();

    extern objc_class OBJC_CLASS_$___NSUnrecognizedTaggedPointer;
    uintptr_t slot, ptr = (uintptr_t)this;
    Class cls;

    slot = (ptr >> _OBJC_TAG_SLOT_SHIFT) & _OBJC_TAG_SLOT_MASK;
    cls = objc_tag_classes[slot];
    if (slowpath(cls == (Class)&OBJC_CLASS_$___NSUnrecognizedTaggedPointer)) {
        slot = (ptr >> _OBJC_TAG_EXT_SLOT_SHIFT) & _OBJC_TAG_EXT_SLOT_MASK;
        cls = objc_tag_ext_classes[slot];
    }
    return cls;
}

来到objc-object.h中的ISA()

inline Class 
objc_object::ISA() 
{
    ASSERT(!isTaggedPointer()); 
#if SUPPORT_INDEXED_ISA
    if (isa.nonpointer) {
        uintptr_t slot = isa.indexcls;
        return classForIndex((unsigned)slot);
    }
    return (Class)isa.bits;
#else
    return (Class)(isa.bits & ISA_MASK);
#endif
}

原来重写了isaget方法,通过isa.bits & ISA_MASK获取bits里面存储的类信息,然后强转成Class类型

上一篇 下一篇

猜你喜欢

热点阅读