1.SEL与IMP
SEL: 相当于一个房子的地址,通过这个地址可以找到你的房子. IMP: 方法的具体实现,也就算相当于你的这栋房子的所有东西
我们开发中经常指派一个button的点击事件selector,实际上就是通过SEL去 找到对应的按钮事件的具体实现
macho - 绑定symbol - 按钮的action(SEL) - 点击事件具体实现(IMP)
2.什么是isa
官方说明: A pointer to the class definition of which this object is an instance.
一个指向当前实例对象所属类的指针.
我们在创建一个实例对象, 进行alloc的时候, 底层会进行对isa的一个初始化.那么这个实例对象的第一个属性一定是isa.
isa它是来源于NSObject这个类.
3.isa关联对象和类
一个isa既然是当前实例对象所属类的指针, 那么它必然与cls有所关联
首先我们实例化一个对象
MyTest *test = [MyTest alloc];
输出一下这个对象的isa
再来看一下MyTest这个类的cls
obj->initInstanceIsa(cls, dtor);
字面意思就是isa的初始化, 进入具体实现
inline void
objc_object::initInstanceIsa(Class cls, bool hasCxxDtor)
{
assert(!cls->instancesRequireRawIsa());
assert(hasCxxDtor == cls->hasCxxDtor());
initIsa(cls, true, hasCxxDtor);
}
进入initIsa
可以看到底层是创建一个newisa, isa与cls关联就是cls向右平移了三位等于isa的shiftcls属性 那么在之前我们打印的 MyTest二进制数据向右平移三位
进入isa_t看一下isa的具体结构
发现isa的本质是一个联合体,进入ISA_BITFIELD.
在x86环境下清楚的看到shiftcls占用了44位,shiftcls之前还有3位,这就是cls向右平移3位的原因所在 那么我们只需要shiftcls这一部分 为了方便观察:
3.1方法二:
isa既然与cls关联,我们可以通过object_getClass去获取到这个类信息.
进入object_getClass底层实现
4.isa的指向分析
4.1类与元类
对象可以创建多个,但是在内存中,类只有一个. 分析:
MyTest *test = [MyTest alloc];
Class class1 = [MyTest class];
Class class2 = [MyTest alloc].class;
Class class3 = object_getClass([MyTest alloc]);
Class class4 = test.class;
NSLog(@"\n%p --- \n%p --- \n%p --- \n%p --- ", class1, class2, class3, class4);
得到结果:
我们都知道, 一个对象内存的isa指向的是一个类的内存空间,来打印一下类的内存空间
总结一下概念: 对象: 我们根据类来实例化出来的. 类: 我们代码写出来的,它在内存中只存在一份.肯定不是我们创建出来的,是系统通过我们的代码创建了类. 元类: 系统在编译的时候,发现有了这么一个类,就为了方便,就会在中间产生了另外一种结构, 就是元类.我们是实例化不出来的,是由编译器编译阶段产生的.
4.2元类的指向
我们都知道对象的isa会指向一个类对象, 类对象又是指向元类. 那么元类指向哪里呢? 我们可以通过获取类的方法来探索, 实际上就上探索isa的走位. 既然知道一个类的第一个位置是指向元类
总结: isa走位: 实例对象 -> 类 -> 元类 -> 根元类 <-> 根元类 例: test -> MyTest -> MyTest(元类) -> NSObject(元类) <-> NSObject(元类)
附图: