从NSObject开始了解isa

几乎所有的类都是继承自NSObject开始实现的,所有这篇文章我们也将从NSObject类开始来了解对象的创建及isa,文章也将从runtime源码开始让读者了解isa究竟是什么东西。

一:对象分解

NSObject* object = [[NSObject alloc] init];

NSObject* object = (((id)((NSObject *(*)(id, SEL))(void *)objc_msgSend)
((id)objc_getClass("NSObject"), sel_registerName("alloc")), sel_registerName("init"));

分析:上面我通过命令 clang -rewrite-objc xx.m 将OC代码转换为C++源码,我们会发现这里其实就是先调用alloc方法,再进一步调用init方法。

二:对象创建过程

// NSObject.mm
+ (id)alloc {
    return _objc_rootAlloc(self);
}
id _objc_rootAlloc(Class cls)
{
    return callAlloc(cls, false/*checkNil*/, true/*allocWithZone*/);
}
callAlloc(Class cls, bool checkNil, bool allocWithZone=false)
{
    if (fastpath(!cls->ISA()->hasCustomAWZ())) {
        if (fastpath(cls->canAllocFast())) {  存在快速alloc方法实现
            bool dtor = cls->hasCxxDtor();  获取对象是否存在析构器
            id obj = (id)calloc(1, cls->bits.fastInstanceSize());  创建对象
            if (slowpath(!obj)) return callBadAllocHandler(cls);  若失败则执行修复对象内部操作
            obj->initInstanceIsa(cls, dtor);  初始化对象
            return obj;
        }
        else {
            id obj = class_createInstance(cls, 0);  创建对象
            return obj;
        }
    }
}

分析:对象创建过程程序会调用_objc_rootAlloc方法,再通过方法callAlloc去实现对象地创建。

三:对象初始化

objc_object::initInstanceIsa(Class cls, bool hasCxxDtor)
{
    initIsa(cls, true, hasCxxDtor);  初始化方法
}
objc_object::initIsa(Class cls, bool nonpointer, bool hasCxxDtor) 
{ 
    if (!nonpointer) {
        isa.cls = cls;
    } else {
        isa_t newisa(0);

#if SUPPORT_INDEXED_ISA
        newisa.bits = ISA_INDEX_MAGIC_VALUE;
        newisa.has_cxx_dtor = hasCxxDtor;
        newisa.indexcls = (uintptr_t)cls->classArrayIndex();
#else  iOS执行这部分代码
        newisa.bits = ISA_MAGIC_VALUE;
        newisa.has_cxx_dtor = hasCxxDtor;
        newisa.shiftcls = (uintptr_t)cls >> 3;
#endif
        isa = newisa;
    }
}

执行initInstanceIsa方法进行对象参数的初始化。

#   define ISA_MAGIC_VALUE 0x001d800000000001ULL

ISA_MAGIC_VALUE的值转换成二进制,我们会发现isa_t的magic和nonpointer都被进行了初始化设置。

nonpointer为0时,访问对象isa会返回一个指向cls的指针。也就是在 iPhone 迁移到 64 位系统之前时 isa 的类型;

nonpointer为1时,shiftcls才是指向cls的指针,也即是isa对象地址将是存放在shiftcls中,但isa还是保存了一些cls的信息。

magic则是判断对象是否已经初始化;

has_cxx_dtor是判断对象是否存在析构器,若不存在的话,内存释放将会加快;

newisa.shiftcls = (uintptr_t)cls >> 3;

shiftcls是当前对象指向了类cls的指针。假设当前类cls地址为100000000001110101110000011111000,由于后面三位都为0,所以右移3位可以将不需要用到的位空出来,为 isa 留下 34 位用于性能的优化。

四:isa_t对象的其它属性:

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

    Class cls;
    uintptr_t bits;
# if __arm64__
#   define ISA_MASK        0x0000000ffffffff8ULL
#   define ISA_MAGIC_MASK  0x000003f000000001ULL
#   define ISA_MAGIC_VALUE 0x000001a000000001ULL
    struct {
        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;
    };
}

has_assoc是判断对象是否有关联,没有可加速内存地释放;

weakly_referenced是对象指向弱引用的变量,没有也可加速内存释放;

deallocating是对象正在释放中;

has_sidetable_rc是对象的引用计数太大了;

extra_rc是对象引用计数减1;

 

总结:

以上则是对NSObject对象的objc源码解析及isa类指针信息的说明,只不过现在直接获取isa对象是不允许,直接会报错误,毕竟有些对象类似NSString有时候被优化成TaggedPointer指针了,其实不是一个对象,不能通过isa对其进行操作。

 

参考文献:

从 NSObject 的初始化了解 isa

神经病院 Objective-C Runtime 入院第一天

ARM64 and You

Tagged Pointer作用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值