探究对象与isa
摘要
:本篇主要探究对象的本质以及对象和isa的关系
对象的探究
在OC中,我们常见到以下写法
Test *t = [Test alloc];
一个类调用alloc方法,得到的返回值就是一个类的指针,也就是一个对象。那么,我们只要探究alloc方法的返回值,就可以探究类的本质
那么接下来我们就前往objc源码一探究竟。
源码地址
1.源码探究
经过不停的追溯,我们可以发现,alloc的返回值就是一个名为 initIsa 的函数的返回值,那我们就来看一下这个函数的源码
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);
#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的初始化并且返回isa的值。
代码从上往下看,首先判断是不是 nonpointer(非纯指针)的isa,如果是 nonpointer 的isa,则将cls赋值给isa的cls。当然,实际情况中更多的是 nonpointer isa,继续向下看,SUPPORT_INDEXED_ISA 这个宏的值为0,那么,也就是说,initIsa 最主要做的操作,就是else中的那一部分。
那这个else主要做了些啥呢。从表面上看就是给isa进行初始赋值,那我们就继续看看 isa 到底是个什么。
通过代码追溯,我们可以看到 isa 是 isa_t 类型的,以下是isa_t的代码
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是个联合体,联合体中数据共用一块内存。可以看到 ISA_BITFIELD 中定义了以下内容
# define ISA_MASK 0x00007ffffffffff8ULL
# 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
其中 shiftcls 即为存储的类的指针
2.isa与类的关系
iOS的开发者有个常用的api叫 object_getClass ,我们可以看一下,系统是如何拿到这个类的。点击源码可以看见如下代码
Class object_getClass(id obj)
{
if (obj) return obj->getIsa();
else return Nil;
}
inline Class
objc_object::getIsa()
{
if (!isTaggedPointer()) return ISA();
uintptr_t ptr = (uintptr_t)this;
if (isExtTaggedPointer()) {
uintptr_t slot =
(ptr >> _OBJC_TAG_EXT_SLOT_SHIFT) & _OBJC_TAG_EXT_SLOT_MASK;
return objc_tag_ext_classes[slot];
} else {
uintptr_t slot =
(ptr >> _OBJC_TAG_SLOT_SHIFT) & _OBJC_TAG_SLOT_MASK;
return objc_tag_classes[slot];
}
}
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
}
可以看到,如果是 nonpointer,就返回 isa 的 bits,如果不是 nonpointer isa,则是用 bits &运算一个Mask(掩码)返回这个值
那么isa就是一个对象的信息存储,其中类的信息也包含在isa中
我们可以用lldb去验证一下
总结
isa是对象的一个属性,它包含了包括对象的类等一些关于对象的信息