iOS-isa的初始化&指向分析

668 阅读3分钟

1:what is isa?

isa结构

2:isa初始化 & isa <-> cls 关联

一个NSObject对象的第一个属性必然是isa。

isa <-> cls 关联

查看源码isa 的初始化:

inline void 
objc_object::initIsa(Class cls, bool nonpointer, bool hasCxxDtor) 
{ 
    assert(!isTaggedPointer()); 
    
    if (!nonpointer) {
        isa.cls = cls;//将cls与isa 关联上。
    } else {
        assert(!DisableNonpointerIsa);
        assert(!cls->instancesRequireRawIsa());

        isa_t newisa(0);

#if SUPPORT_INDEXED_ISA//0
        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;
        //uintptr_t:unsigned long  偏移后的cls,将cls与isa 关联上。
        newisa.shiftcls = (uintptr_t)cls >> 3;
#endif

        isa = newisa;
    }
}

发现isa与cls关联在了一起,验证关联:

sample:
LGTeacher *p = [LGTeacher alloc];
Class objct = object_getClass(p);

//lldb 打印 $4$6值一样
(lldb) p/x LGTeacher.class
(Class) $4 = 0x0000000100001448 LGTeacher
(lldb) x/4xg p
0x101961ab0: 0x001d80010000144d 0x0000000000000000
0x101961ac0: 0x0000000000000000 0x0000000000000000
(lldb) p/x 0x001d80010000144d & 0x00007ffffffffff8
(long) $6 = 0x0000000100001448

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
    return (Class)(isa.bits & ISA_MASK);//#   define ISA_MASK x86的     0x00007ffffffffff8ULL
#endif
}

3:isa & superClass 走位图

走位图
从源码中得知 cls = isa.bits & ISA_MASK,根据这个可以打印对象的 isa & ISA_MASK 判断是否与类的地址相同,来验证isa 的走位是否正确。

a sample:
LGPerson *object = [LGPerson alloc];//继承自NSObject

//1:检查实例对象内存
(lldb) x/4gx object    
0x101120ba0: 0x001d800100001131 0x0000000000000000
0x101120bb0: 0x0000000000000002 0x00007fff9e64e898

(lldb) po 0x101120ba0
<LGPerson: 0x101120ba0>

//  0x001d800100001131 就是isa
// 通过 & ISA_MASK 运算可以得到 类对象 地址
//#   define ISA_MASK        0x00007ffffffffff8ULL (x86下)
(lldb) p/x 0x001d800100001131 & 0x00007ffffffffff8ULL
(unsigned long long) $25 = 0x0000000100001130
(lldb) po 0x0000000100001130    得到类对象地址
LGPerson    //实例对象的类对象为LGPerson

// 2:检查 类对象 内存
(lldb) x/4gx 0x0000000100001130
0x100001130: 0x001d800100001109 0x0000000100b35140
0x100001140: 0x0000000100f6df70 0x0000000400000007

//0x001d800100001109是类对象的isa ,此isa指向的是元类对象
(lldb) p/x 0x001d800100001109 & 0x00007ffffffffff8ULL
(unsigned long long) $31 = 0x0000000100001108 //得到元类对象地址
(lldb) po 0x0000000100001108    
LGPerson        conclusion:类对象isa 指向元类对象

//第二个0x0000000100b35140是 superclass (从这里看到了继承关系),实例对象第二个空间是空的
//只有isa 经过了 & ISA_MASK处理,superclass 存储的就是纯指针
(lldb) po 0x0000000100b35140
NSObject    //得到父类

//3:查看元类对象地址0x0000000100001108
(lldb) x/4gx 0x0000000100001108
0x100001108: 0x001d800100b350f1 0x0000000100b350f0
0x100001118: 0x000000010122d320 0x0000000300000007

//这里的isa指向的是元类对象
(lldb) p/x 0x001d800100b350f1 & 0x00007ffffffffff8ULL
(unsigned long long) $34 = 0x0000000100b350f0
(lldb) po 0x0000000100b350f0
NSObject        //conclusion:元类isa指向根元类对象

//第二个是 superclass
//元类的继承与类是差不多的,继承自根元类(Meta Root Class)
(lldb) po 0x0000000100b350f0
NSObject

//4:检查根元类对象地址0x0000000100b350f0
(lldb) x/4gx 0x0000000100b350f0
0x100b350f0: 0x001d800100b350f1 0x0000000100b35140
0x100b35100: 0x0000000100f6e320 0x0000000400000007

(lldb) p/x 0x001d800100b350f1 & 0x00007ffffffffff8ULL
(unsigned long long) $38 = 0x0000000100b350f0
(lldb) po 0x0000000100b350f0
NSObject        //conclusion:这里根元类isa指向的是自己 

//第二个是 superclass
//根据之前检查 0x0000000100b35140 是NSObject (基类)
(lldb) po 0x0000000100b35140
NSObject        //conclusion :根元类 的superclas指向了基类,也就是继承自基类 

至此以上sample验证isa走位图。