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初始化
- 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);
}
- 当nonpointer = false,代表当前为普通指针,那么直接通过isa.cls和类进行关联
- 当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走位