OC 底层

iOS底层原理之isa分析

2019-12-22  本文已影响0人  尘舒

1.isa本质

我们知道,oc中的一切类都继承自NSObject,直接追踪NSObject可以发现在objc/NSObject.h文件中对于该类的定义如下

@interface NSObject <NSObject> {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-interface-ivars"
    Class isa  OBJC_ISA_AVAILABILITY;
#pragma clang diagnostic pop
}

或者在objc源码中找到关于类在C语言层面的定义

struct objc_object {
    Class _Nonnull isa  OBJC_ISA_AVAILABILITY;
};
typedef struct objc_class *Class;
struct objc_class : objc_object {
    // Class ISA;
    Class superclass;
    cache_t cache;             // formerly cache pointer and vtable
    class_data_bits_t bits;    // class_rw_t * plus custom rr/alloc flags

    class_rw_t *data() { 
        return bits.data();
    }
}
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
};


struct objc_object {
private:
    isa_t isa;

public:

    // ISA() assumes this is NOT a tagged pointer object
    Class ISA();

    // getIsa() allows this to be a tagged pointer object
    Class getIsa();
}

2.isa初始化

objc_object::initIsa(Class cls, bool nonpointer, bool hasCxxDtor) 
{ 
    assert(!isTaggedPointer()); 
    
    if (!nonpointer) {
        isa.cls = cls;
    } else {
        assert(!DisableNonpointerIsa);
        assert(!cls->instancesRequireRawIsa());

        isa_t newisa(0);

#if SUPPORT_INDEXED_ISA
    // 此处有一些代码,不过不重要,暂时不会走这里
#else
        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;
        newisa.shiftcls = (uintptr_t)cls >> 3;
#endif

        isa = newisa;
    }
}

3.isa对类和对象的关联

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

objc_object::getIsa() 
{
    // 一般都不是TaggedPointer,这是特殊指针
    if (!isTaggedPointer()) return ISA();
}

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
}
// 64位架构下 ISA_MASK的值为
#   define ISA_MASK        0x00007ffffffffff8ULL

4.类中isa的指向

问题来了,按照刚才的步骤打印出了类的地址,但是通过isa指针寻找之后得到地址0x0000000100001108,并且打印值和之前打印类一样均为LGPerson,但是二者的地址却截然不同,我们知道,类在内存中只可能存在一份,对象可以存在多份,那么可以推断,当前0x0000000100001108是一个和LGPerson名字相同但是却不一样的类,姑且认为它是 LG-A

总结:

上一篇 下一篇

猜你喜欢

热点阅读