iOS Runtime之方法查找
2022-06-23 本文已影响0人
谢二九
Runtime系列导读
介绍
OC是一门动态性比较强的编程语言,允许很多操作推迟到程序运行时再进行。
OC的动态性就是由Runtime来支撑和实现的,Runtime是一套C语言的API,封装了很多动态性相关的函数平时编写的OC代码,底层都转换成Runtime API(主要是objc_msgSend和objc_msgSendSuper)进行调用。
我们可以利用Runtime做以下具体场景应用:
- 关联对象(AssociatedObject)给分类添加属性;
- 遍历类的所有成员变量;
- 交换方法实现;
- 利用消息转发机制解决方法找不到的异常问题
方法存储
实例对象与类的关系
定义
科普下实例对象(instance)、类(class)、元类(meta-class)。
- 类在面向对象编程中是一种面向对象计算机编程语言的构造,描述了所创建的对象共同的属性和方法。
- 实例对象是根据某个类创建的对象。
- 元类:是一种实例是类的类。
综上总结,类是实例对象的描述,元类是类对象的描述。
模型
实例对象的存储结构(以NSObject实例对象举例):
struct NSObject_IMP{
Class isa;
}
其中,isa是指向NSObject类的指针。
类对象的存储结构
struct objc_class {
Class _Nonnull isa;
Class _Nullable super_class;
struct objc_ivar_list * _Nullable ivars;
struct objc_method_list * _Nullable * _Nullable methodLists;
struct objc_cache * _Nonnull cache;
struct objc_protocol_list * _Nullable protocols;
...
}
其中,
- isa是指向元类的指针
- super_class是指向父类的指针
- ivars是指向成员变量的指针
- methodLists是指向方法列表的指针
- cache是指向方法缓存的指针
- protocols是指向协议的指针
关系
通过源码分析,可以确认实例对象、类和元类是以下关系:
- 实例对象的isa指向类
- 类的isa指向元类
- 元类的isa指向基类的元类
- 类的superclass指向父类。如果没有父类,superclass指针为nil
- 元类的superclass指向父类的元类。基类的元类的superclass指向基类
- 实例对象调用实例方法,是通过isa找到类,如不存在则通过superclass找父类
- 类调用类方法,是通过isa找元类,如不存在则通过superclass找父类
消息发送
消息发送从类对象或者元类的方法列表缓存和方法列表中查,没有则通过super指针逐级向上,有则缓存并调用。
动态方法解析
开发者可以实现以下方法,来动态添加方法实现:
- +resolveInstanceMethod:
- +resolveClassMethod:
动态解析过后,会重新走“消息发送”的流程,“从receiverClass的cache中查找方法”这一步开始执行。
消息转发
- a转发给谁处理 - (id)forwardingTargetForSelector:(SEL)aSelector{}
- b获取方法签名 - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{}
- c自定义转发逻辑 - (void)forwardInvocation:(NSInvocation *)anInvocation{}
延伸问题
- 方法模型结构
- 方法缓存什么场景下会清理
- NSProxy用法