对象的isa指针指向哪里?

138 阅读2分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。


先从OC的调用方法开始\

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

// 实例对象调用对象方法:

[obj objInstanceMethod];

调用方法其实是发送消息;

objc_msgSend(obj,@selector(objInstanceMethod));

// 类对象调用类方法:

[NSObject objClassMethod];

objc_msgSend([NSObject class],@selector(objClassMethod));

调用实例对象的实例方法,首先要找到对象方法。

由于实例对象中并没有对象方法。实例对象的方法放在class对象的方法列表中。

调用类方法,首先要找到类方法。

由于类对象中并没有类方法。类方法放在meta-class对象的方法列表中

这就要求instance    class    meta-class 必须存在某种关系。

实际上,这种关系就是通过isa指针来维持的。

640-1.jpeg

instance对象的isa指向class对象

当调用instance对象方法时,通过instance的isa找到类对象方法列表中对应的方法,然后再找到方法实现进行调用。

class对象的isa指向meta-class对象

当调用类方法时,通过class的isa找到meta-class,最后

找到meta-class对象中存储的类方法,再找到类方法的实现进行调用。

按道理讲:

instance实例对象的isa指针存放的是 类对象的地址。

类对象的disa指针存放的是 meta-class类对象的地址。

但实际上,经过测试:

例子:

instance实例对象的isa: 0x001d8001000014c9

               类对象的地址: 0x00000001000014c8

发现实例对象的isa指针并没有保存类对象的地址。

这是什么问题呢?

实际上:在以前的设备中 isa存储的值就是 类对象的值。

但是从64位开始,就不是了。

isa需要 & ISA_MASK之后才是 类对象的地址值。

注意:&  与操作,可以自己科普C语言的 & 操作。

ISA_MASK值在苹果的源码中是这样的。

640-2.jpeg

我们将:isa & 0x00007ffffffffff8 取与操作:得到的结果正好是 0x00000001000014c8 正是 class对象的结果。

 0x001d8001000014c9 & 0x00007ffffffffff8  =  0x00000001000014c8