3、iOS底层分析 — isa的初始化&指向分析

isa

通过查看类的源码 objc_class 可以发现里面有一个隐藏的属性 ISA

objc_class 中的ISA是隐藏的,是来自于父类 objc_object。

这个ISA 是什么呢?

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();
    }
    void setData(class_rw_t *newData) {
        bits.setData(newData);
    }

1、什么是ISA

通过搜索查看,可以找到 ISA 定义的源码发现其继承自objc_object,objc-private.h

(某位大神研究了新版和旧版的却别,由于现在都是用的是objc2.0所以就不去研究旧版的了摘过来知道就行了:实际上在旧版的代码中,objc_class是一个单纯的结构体,在new版本的代码中才继承自objc_object,这也符合了面向对象中,万物皆对象的理念。在objc-runtime-new.h文件中可以看到,之后寻找objc_object的初始定义,最终在objc-private.h文件中发现了最初始的object定义以及isa的详细结构)

isa是一个联合体位域,里面关联了它所指向的类,也就是Class cls

联合体的内的属性是互斥的,赋值了cls 就没必要赋值 bits。他们只有一个存在。

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

2、isa初始化

  1. alloc 初始化的时候调用 class_createInstance
id 
class_createInstance(Class cls, size_t extraBytes)
{
    return _class_createInstanceFromZone(cls, extraBytes, nil);
}

    2. _class_createInstanceFromZone 中同时初始化了ISA

obj->initIsa(cls);

static __attribute__((always_inline)) 
id
_class_createInstanceFromZone(Class cls, size_t extraBytes, void *zone, 
                              bool cxxConstruct = true, 
                              size_t *outAllocatedSize = nil)
{
。。。。。。
    // Read class's info bits all at once for performance
    bool hasCxxCtor = cls->hasCxxCtor();
    bool hasCxxDtor = cls->hasCxxDtor();
    bool fast = cls->canAllocNonpointer();

    size_t size = cls->instanceSize(extraBytes);
    if (outAllocatedSize) *outAllocatedSize = size;

    id obj;
    if (!zone  &&  fast) {
        obj = (id)calloc(1, size);
        if (!obj) return nil;
        obj->initInstanceIsa(cls, hasCxxDtor);
    } 
    else {
        if (zone) {
            obj = (id)malloc_zone_calloc ((malloc_zone_t *)zone, 1, size);
        } else {
            obj = (id)calloc(1, size);
        }
        if (!obj) return nil;

        // Use raw pointer isa on the assumption that they might be 
        // doing something weird with the zone or RR.
        obj->initIsa(cls);
    }
。。。。。。
}
inline void 
objc_object::initIsa(Class cls)
{
    initIsa(cls, false, false);
}
  1. 当nonpointer = false,代表当前为普通指针,那么直接通过isa.cls和类进行关联
  2. 当nonpointer = true 的时候,代表是优化过的isa指针,会使用位域存放更多的信息,此时创建newisa并初始化值后赋值给isa指针
inline void 
objc_object::initInstanceIsa(Class cls, bool hasCxxDtor)
{
    assert(!cls->instancesRequireRawIsa());
    assert(hasCxxDtor == cls->hasCxxDtor());

    initIsa(cls, true, hasCxxDtor);
}

inline void 
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);

isa是class类型包含了类的所有信息

通过分析isa的初始化可以发现,isa是class类型,初始化的时候是将cls赋值给了isa。那么isa就有了类的所有信息。

我们万物皆对象,类也是类对象,类的根类是NSObject,那我们去看一下NSObject

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

objc

struct objc_object {
    Class _Nonnull isa  OBJC_ISA_AVAILABILITY;
};
typedef struct objc_class *Class;

由此可以知道isa的类型是objc_class 的结构体指针,每个类里面都有这么一个isa的指针属性。

虽然知道isa是个指针(类指针),里面存放什么呢?又是指向谁呢?

3、isa指向分析

既然知道isa 的类型是一个class,那就是跟类有关,先看一下类的获取吧

Class object_getClass(id obj)
{
    if (obj) return obj->getIsa();
    else return Nil;
}
inline Class 
objc_object::getIsa() 
{
    if (!isTaggedPointer()) return 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
这个地方通过掩码来获取实际需要的的isa
    return (Class)(isa.bits & ISA_MASK);
#endif
}
# elif __x86_64__
#   define ISA_MASK        0x00007ffffffffff8ULL

3.1、对象isa的指向

打印对象的属性(X/4gx 是打印对象4个属性),由对象的底层代码可知,第一位就是isa。

然后通过掩码  isa.bits & ISA_MASK 得到指向

猜测是类,p/x(打印类的十六进制) 一下类做一下对比看一下。

发现是一样的,所以可以证明对象的isa是指向类

3.2、类的isa指向

类的isa 指向的是元类

总结

苹果官方提供的isa走位

发布了83 篇原创文章 · 获赞 12 · 访问量 18万+

猜你喜欢

转载自blog.csdn.net/shengdaVolleyball/article/details/104030446