isa
isa到底是什么?在官方的解释中是这样的
Every object is connected to the run-time system through itsisa instance variable, inherited from the NSObject class.isa identifies the object's class; it points to a structurethat's compiled from the class definition. Through isa, anobject can find whatever information it needs at run timesuch asits place in the inheritance hierarchy, the size and structure ofits instance variables, and the location of the methodimplementations it can perform in response to messages.
翻译过来的意思就是 每个对象都通过从NSObject类继承的isa实例变量来连接到运行时系统。 它指向从类定义编译的结构。 通过isa,对象可以找到运行时所需的任何信息,例如其在继承层次结构中的位置,其实例变量的大小和结构以及可以响应消息执行的方法实现的位置。
isa的结构内存对齐&isa已经提到了,isa初始化如下
inline void
objc_object::initIsa(Class cls, bool nonpointer, bool hasCxxDtor)
{
assert(!isTaggedPointer());
if (!nonpointer) {//现在都是nonpointer 所以走else
isa.cls = cls;
} else {
assert(!DisableNonpointerIsa);
assert(!cls->instancesRequireRawIsa());
isa_t newisa(0);
#if SUPPORT_INDEXED_ISA //#define SUPPORT_INDEXED_ISA 0 也走else
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和类存在绑定关系newisa.shiftcls = (uintptr_t)cls >> 3,我们来验证一下
//_x86模式下
# elif __x86_64__
# 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
(lldb) x/4gx p
0x102f7d410: 0x001d800100002535 0x0000000000000000
0x102f7d420: 0x0000000000000000 0x0000000000000000
// 第一个参数就是isa 打印isa的二进制信息
(lldb) p/t 0x001d800100002535
(long) $1 = 0b0000000000011101100000000000000100000000000000000010010100110101
// isa->shiftcls 占44位,前面被其他信息占了3位,后面被其他信息占了17位,
// 右移3位清空其他信息
(lldb) p/t $1 >> 3
(long) $4 = 0b0000000000000011101100000000000000100000000000000000010010100110
// 左移17位清空其他信息
(lldb) p/t $4 << 17
(long) $5 = 0b0110000000000000010000000000000000001001010011000000000000000000
//还原 得出 shiftcls
(lldb) p/t $5 >> 17
(long) $6 = 0b0000000000000000001100000000000000100000000000000000010010100110
// 类右移3位得到 isa->shiftcls
(lldb) p/t (uintptr_t)LGTeacher.class >> 3
(uintptr_t) $2 = 0b0000000000000000000000000000000000100000000000000000010010100110
lldb扩展:x/4gx p打印p的4段内存信息。同理:x/6gx就是打印6段内存信息。p/t打印二进制信息p/o打印八进制信息p/d打印十进制信息p/x打印十六进制信息
可见$6和$2后面44位都是00000000000000100000000000000000010010100110,验证了对象初始化的isa与class绑定关系。
有没有更加简单的方法来验证呢?
Class object_getClass(id obj){
if (obj) return obj->getIsa();
else return Nil;
}
inline Class objc_object::getIsa() {
if (!isTaggedPointer()) return ISA();
}
# if __arm64__
# define ISA_MASK 0x0000000ffffffff8ULL
# elif __x86_64__
# define ISA_MASK 0x00007ffffffffff8ULL
# else
# error unknown architecture for packed isa
# endif
inline Class objc_object::ISA() {
...
return (Class)(isa.bits & ISA_MASK);
...
}
关键代码(Class)(isa.bits & ISA_MASK),我们来验证一下
(lldb) x/4gx p
0x102f7d410: 0x001d800100002535 0x0000000000000000
0x102f7d420: 0x0000000000000000 0x0000000000000000
/通过对象的isa & ISA_MASK
(lldb) p/x 0x001d800100002535 & 0x00007ffffffffff8
(long) $9 = 0x0000000100002530
//打印类的地址
(lldb) p/x LGTeacher.class
(Class) $7 = 0x0000000100002530 LGTeacher
$7和$9一模一样
isa的指向分析(isa走位)
通过lldb调试来查看isa的指向走位
LGTeacher *p = [LGTeacher alloc];
(lldb) x/4gx p
0x102f7d410: 0x001d800100002535 0x0000000000000000
0x102f7d420: 0x0000000000000000 0x0000000000000000
(lldb) p/x 0x001d800100002535 & 0x00007ffffffffff8
(long) $11 = 0x0000000100002530
(lldb) po 0x0000000100002530
LGTeacher
p对象的isa & ISA_MASK获取到了类的信息。即isa从类的实例对象p指向了类LGTeacher
(lldb) x/4gx $11
0x100002530: 0x001d800100002509 0x0000000100b34140
0x100002540: 0x00000001003d7290 0x0000000000000000
(lldb) p/x 0x001d800100002509 & 0x00007ffffffffff8
(long) $13 = 0x0000000100002508
(lldb) po $13
LGTeacher
- 通过类的
isa & ISA_MASK获取到了另外一个类的信息。即isa从类LGTeacher又指向了类LGTeacher(其实这个类是我们LGTeacher的metaClass元类)。编译器会把一个类作为它的元类的实例化对象来处理,就像一个对象从类实例化出来。
(lldb) x/4gx $13
0x100002508: 0x001d800100b340f1 0x0000000100b340f0
0x100002518: 0x0000000102100040 0x0000000300000007
(lldb) p/x 0x001d800100b340f1 & 0x00007ffffffffff8
(long) $14 = 0x0000000100b340f0
(lldb) po $14
NSObject
- 元类的
isa & ISA_MASK获取到了另外一个类NSObject的信息。即isa从元类LGTeacher又指向了类NSObject
(lldb) x/4gx $14
0x100b340f0: 0x001d800100b340f1 0x0000000100b34140
0x100b34100: 0x0000000100f45ae0 0x0000000400000007
- 可以看到了第三步的
isa与第四步的isa是同一片内存地址。
由此得出的isa的指向关系为:对象 -> 类 -> 元类 -> 根元类 -> 根元类
通过代码验证也是一样的
// NSObject实例对象
NSObject *object1 = [NSObject alloc];
// NSObject类
Class class = object_getClass(object1);
// NSObject元类
Class metaClass = object_getClass(class);
// NSObject根元类
Class rootMetaClass = object_getClass(metaClass);
// NSObject根根元类
Class rootRootMetaClass = object_getClass(rootMetaClass);
NSLog(@"\n%p 实例对象\n%p 类\n%p 元类\n%p 根元类\n%p 根根元类",object1,class,metaClass,rootMetaClass,rootRootMetaClass);
0x100500540 实例对象
0x7fff9aaeb118 类
0x7fff9aaeb0f0 元类
0x7fff9aaeb0f0 根元类
0x7fff9aaeb0f0 根根元类

类的继承关系
有LGTeacher->LGPerson->NSObject,类内存信息中的第二个地址指向是superClass(这个位置后面的章节会探索到)
(lldb) x/4gx LGTeacher.class
0x100002530: 0x001d800100002509 0x0000000100002580
0x100002540: 0x00000001003d7290 0x0000000000000000
(lldb) po 0x0000000100002580
LGPerson //LGTeacher的父类为LGPerson
(lldb) x/4gx 0x0000000100002580
0x100002580: 0x001d800100002559 0x0000000100b34140
0x100002590: 0x00000001003d7290 0x0000000000000000
(lldb) po 0x0000000100b34140
NSObject //LGPerson的父类为NSObject
(lldb) x/4gx 0x0000000100b34140
0x100b34140: 0x001d800100b340f1 0x0000000000000000
0x100b34150: 0x00000001021152a0 0x0000000200000003
(lldb) po 0x0000000000000000
<nil> //NSObject的父类为nil
结论:
类的继承关系:LGTeacher->LGPerson->NSObject->nil
元类的继承关系
(lldb) x/4gx LGTeacher.class
0x100002530: 0x001d800100002509 0x0000000100002580
0x100002540: 0x00000001003d7290 0x0000000000000000
(lldb) p/x 0x001d800100002509 & 0x00007ffffffffff8
(long) $5 = 0x0000000100002508 //LGTeacher的元类
(lldb) x/4gx 0x0000000100002508
0x100002508: 0x001d800100b340f1 0x0000000100002558
0x100002518: 0x0000000100ff9500 0x0000000300000003
1.获取LGTeacher的元类的父类为0x0000000100002558
(lldb) x/4gx 0x0000000100002580 //LGPerson
0x100002580: 0x001d800100002559 0x0000000100b34140
0x100002590: 0x00000001003d7290 0x0000000000000000
(lldb) p/x 0x001d800100002559 & 0x00007ffffffffff8
(long) $6 = 0x0000000100002558 //LGPerson的元类
(lldb) po 0x0000000100002558
LGPerson
2.获取LGTeacher的父类的元类为0x0000000100002558,得出LGTeacher的元类->LGPerson的元类
(lldb) x/4gx 0x0000000100002558 //LGPerson的元类
0x100002558: 0x001d800100b340f1 0x0000000100b340f0
0x100002568: 0x0000000102200370 0x0000000300000003
3.获取LGPerson的元类的父类为0x0000000100b340f0
(lldb) x/4gx 0x0000000100b34140 //NSObjec
0x100b34140: 0x001d800100b340f1 0x0000000000000000
0x100b34150: 0x00000001021152a0 0x0000000200000003
(lldb) p/x 0x001d800100b340f1 & 0x00007ffffffffff8
(long) $8 = 0x0000000100b340f0 //NSObjec的元类
(lldb) po 0x0000000100b340f0
NSObject
4.获取LGPerson的父类的元类为0x0000000100b340f0,得出LGPerson的元类->NSObjec的元类
(lldb) x/4gx 0x0000000100b340f0 //NSObject的元类
0x100b340f0: 0x001d800100b340f1 0x0000000100b34140
0x100b34100: 0x00000001022008b0 0x0000000400000007
(lldb) po 0x0000000100b34140 //NSObject
NSObject
5.获取NSObjec的元类的父类为0x0000000100b34140,得出NSObjec的元类->NSObjec
(lldb) po 0x0000000000000000
<nil>
6.获取NSObjec的父类为0x0000000000000000,得出NSObjec->nil
结论:元类的继承关系:
LGTeacher元类->LGPerson元类->NSObject元类->NSObject->nil
和苹果官方图一模一样

对象 -> 类 -> 元类 -> 根元类 -> 根元类,实线是继承关系,
根元类的父类是NSObject,NSObject的父类是nil