iOS isa初步理解之实例的isa

前言

在iOS开发过程中,最最常见的就是类、对象。分析isa对理解OC类、对象是非常重要的。

一、准备

1、我们先准备一个main.m文件,内容如下

#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        NSObject *objc1 = [[NSObject alloc] init];
        NSLog(@"Hello, World! %@",objc1);
    }
    return 0;
}

使用我们编译器前端clang命令来将main.m 重写成main.cpp,命令如下

$clang -rewrite-objc main.m -o main.cpp

当然你也可以将这个main.m编译成一个可执行文件命令如下

$clang -fobjc-arc -framework Foundation main.m -o main
$./main
//将会打印输出类似  Hello, World! <NSObject: 0x7f9eb1504220>

2、下载我们的OC的objc源码,下载链接:objc4

二、分析

1、我们首先分析main.cpp文件,先找到他的入口main函数,一般在文件最后

image.png

  • 这不跟我们的文件很像吗,我们可以在当前文件找到NSObject的定义
    image.png

    在这里由图可知NSObject是一个objc_object结构体的类型;我们继续找找就可以发现
struct objc_object {
    Class _Nonnull isa __attribute__((deprecated));
};

咦,这里发现了一个Class类型的isa;

  • 那我们找找Class又是个什么鬼?我们又在当前文件找找,原来他的定义大体如下
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 是一个指向结构体objc_class指针类型.并且还注意到,objc_class居然继承于objc_object,里面还有一个Class类型的superclass

  • 讲到这里大家是不是很晕啊,我也是。我们不妨先画一张简单的图,记录一下。


    实例对象isa和类对象的简单关系图

2、刚才是我们分析main.cpp得到的一些信息,接下来我们需要分析objc源码了,看看代码在运行的时候都是怎样指向绑定的。

static ALWAYS_INLINE id
_class_createInstanceFromZone(Class cls, size_t extraBytes, void *zone,
                              int construct_flags = OBJECT_CONSTRUCT_NONE,
                              bool cxxConstruct = true,
                              size_t *outAllocatedSize = nil)
{
    ASSERT(cls->isRealized());

    // Read class's info bits all at once for performance
    bool hasCxxCtor = cxxConstruct && cls->hasCxxCtor();
    bool hasCxxDtor = cls->hasCxxDtor();
    bool fast = cls->canAllocNonpointer();
    size_t size;
    // 1:要开辟多少内存
    size = cls->instanceSize(extraBytes);
    if (outAllocatedSize) *outAllocatedSize = size;

    id obj;
    if (zone) {
        obj = (id)malloc_zone_calloc((malloc_zone_t *)zone, 1, size);
    } else {
        // 2;怎么去申请内存
        obj = (id)calloc(1, size);
    }
    if (slowpath(!obj)) {
        if (construct_flags & OBJECT_CONSTRUCT_CALL_BADALLOC) {
            return _objc_callBadAllocHandler(cls);
        }
        return nil;
    }

    // 3: 绑定isa
    if (!zone && fast) {
        obj->initInstanceIsa(cls, hasCxxDtor);
    } else {
        // Use raw pointer isa on the assumption that they might be
        // doing something weird with the zone or RR.
        obj->initIsa(cls);
    }

    if (fastpath(!hasCxxCtor)) {
        return obj;
    }

    construct_flags |= OBJECT_CONSTRUCT_FREE_ONFAILURE;
    return object_cxxConstructFromClass(obj, cls, construct_flags);
}

1、计算内存;2、开辟内存;3,绑定isa。

我们看到最后的alloc的返回是 一个id的类型

id类型又是什么呢?我们在objc.h找到定义。中文意思就是一个指向class实例的指针;根据代码是指向类型objc_object指针类型

/// A pointer to an instance of a class.
typedef struct objc_object *id;

到这里我们可以得出一条结论:

所有`NSObject`或其子类的`alloc`的方法返回出的类型都是`objc_object *`类型即`id`类型,

不过我们可以看到这里的返回出来的对象其实就是代码里面声明的id obj,我们要看的isa的初始化,其实就在initInstanceIsa这个函数中

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

    initIsa(cls, true, hasCxxDtor);
}

接下来去initIsa看看,

inline void 
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;
        // 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
        newisa.has_cxx_dtor = hasCxxDtor;
        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;
    }
}

这里会创建一个类型为isa_tnewisa,类型isa_t结构定义如下

# 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)

# elif __x86_64__
#   define ISA_MASK        0x00007ffffffffff8ULL
#   define ISA_MAGIC_MASK  0x001f800000000001ULL
#   define ISA_MAGIC_VALUE 0x001d800000000001ULL
#   define ISA_BITFIELD                                                        \
      uintptr_t nonpointer        : 1;                                         \
      uintptr_t has_assoc         : 1;                                         \
      uintptr_t has_cxx_dtor      : 1;                                         \
      uintptr_t shiftcls          : 44; /*MACH_VM_MAX_ADDRESS 0x7fffffe00000*/ \
      uintptr_t magic             : 6;                                         \
      uintptr_t weakly_referenced : 1;                                         \
      uintptr_t deallocating      : 1;                                         \
      uintptr_t has_sidetable_rc  : 1;                                         \
      uintptr_t extra_rc          : 8
#   define RC_ONE   (1ULL<<56)
#   define RC_HALF  (1ULL<<7)

....
....

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_t有两个互斥属性clsbits,并且bits可按位分解为9个子属性.
下面有一张图可以参考一下

isa64情况

通过宏定义分析SUPPORT_INDEXED_ISA

#if __ARM_ARCH_7K__ >= 2  ||  (__arm64__ && !__LP64__)
#   define SUPPORT_INDEXED_ISA 1
#else
#   define SUPPORT_INDEXED_ISA 0
#endif

我们可以的到在arm64的iphone设备上 SUPPORT_INDEXED_ISA=0,
所以知道newisa的会按照联合体的逻辑分配

        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;

3、我们看一下objc_objectisa getter函数

inline Class 
objc_object::getIsa() 
{
    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
    return (Class)(isa.bits & ISA_MASK);
#endif
}

根据前序推理得知在arm64的iphone 上会返回(Class)(isa.bits & ISA_MASK);这个不就是newisa.shiftcls所包含的内容吗(注意,这两个并不相等;一个是64位,一个是64位中的部分)。

根据前面的1、2、3
得出:这个实例(objc_object)的isa是指向了当前的类(objc_class).
这不就是前面画的实例对象isa和类对象的简单关系图吗。

三、总结

1、在目前普遍的机型中arm64或者arm64s,isa是一个联合体类型;
2、实例对象objc_object当调用isa时,其实是调用isa的getter函数ISA(),返回联合体中的(Class)(isa.bits & ISA_MASK);其具体值直线的是类对象objc_class

提问:
这里有一个实例对象isa和类对象的简单关系图;不过我们看到类对象objc_class他是继承于objc_object应该也有一个isa,那它的isa是指向哪里的呢?并且它中间还有一个Class类型(即objc_class *)的supclass又是指向哪呢?
请听下回分解.

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。