小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
先从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指针来维持的。
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值在苹果的源码中是这样的。
我们将:isa & 0x00007ffffffffff8 取与操作:得到的结果正好是 0x00000001000014c8 正是 class对象的结果。
0x001d8001000014c9 & 0x00007ffffffffff8 = 0x00000001000014c8