runtime中实例变量调用方法的步骤:
1.在该实例变量的方法缓存列表中查找方法,如果找到就执行。
2.如果没找到,会在该类结构的方法列表中查找该方法,如果找到就执行。
3.如果没找到,会在该类的父类重复步骤1、2。
4.如果知道根类没找到,就会报错:
unrecognized selector sent to instance 0x1005046c0.
解释:
类结构:
struct objc_class {
Class isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
Class super_class OBJC2_UNAVAILABLE; // 父类
const char *name OBJC2_UNAVAILABLE; // 类名
long version OBJC2_UNAVAILABLE; // 类的版本信息,默认为0
long info OBJC2_UNAVAILABLE; // 类信息,供运行期使用的一些位标识
long instance_size OBJC2_UNAVAILABLE; // 该类的实例变量大小
struct objc_ivar_list *ivars OBJC2_UNAVAILABLE; // 该类的成员变量链表
struct objc_method_list **methodLists OBJC2_UNAVAILABLE; // 方法定义的链表
struct objc_cache *cache OBJC2_UNAVAILABLE; // 方法缓存
struct objc_protocol_list *protocols OBJC2_UNAVAILABLE; // 协议链表
#endif
} OBJC2_UNAVAILABLE;
实例变量的方法缓存列表:常用的方法存在cache列表中,这样查找效率高,如果cache中查找不到,再在methodList中查找,找到后,把方法添加到cache中。在父类中找到方法,添加到自己的cache列表中,而不会添加到methodList中。
类结构的方法列表:methodList,存储该类所有方法。
也就是说
1、重写父类的方法,本质上不是覆盖了父类的方法,只不过是在本类中找到相应的方法,不再去父类中查找方法而已。(即在本类的methodList方法中,添加该方法)
2、super关键字并不是指父类,作用是 跳过此类直接从父类中进行查找方法
动态决议以及请求转发就是拦截上述过程,让其在runtime中运行相应的方法。
动态决议:
请求转发:
如果动态决议和请求转发都实现了,那么动态决议的优先级要高于请求转发.