Runtime
一、数据结构
1、objc_object
id = objc_object : isa_t为共用体
2、objc_class
Class = objc_class: Class也是对象,称之为类对象,因为它继承自onjc_object
3、isa_t
有两种类型,指针型isa、非指针型isa
4、cach_t
5、class_data_bits_t
6、class_rw_t
例如分类1中添加的方法会在methods二维数组中的某个数组中存储
7、class_ro_t
name:类名,可以通过NSClassFromString(name)获取该类
ivars:成员变量
properties:属性
8、method_t
Const char* types: 函数的返回和参数的组合
9、Type Encodings
第一个参数@代表一个对象,第一个参数和第二个参数是固定的,@代表的是谁调用的,也就是self,第二个:表达的是方法选择器
10、对象、类对象、元类对象
Root class指的就是NSObject
如果一个实例方法在元类对象以及根元类对象中都没有,会查找根类对象中的同名实例方法,并调用。
问题
[self class];
[super class];
二、消息传递
1、缓存查找
哈希查找
2、在类对象中查找
3、父类逐级查找
4、消息转发
a、动态解析
我们可以根据方法类型(实例方法or类方法)重写一下方法,为类动态添加方法
+(BOOL)resolveInstanceMethod:(SEL)sel
+(BOOL)resolveClassMethod:(SEL)sel
在方法中调用一下方法来动态添加方法的实现
** 参数1:给哪个类添加
** 参数2:给哪个方法添加
** 参数3:方法的实现地址
** 参数4:方法的编码类型
BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types)
b、消息转发
消息转发分为两步进行: Fast forwarding和 Normal forwarding
1> Fast forwarding : 将消息转发给一个其他的OC对象(找一个备用接收者)
重写以下方法,返回一个其他对象即可
+/- (id)forwardingTargetForSelector:(SEL)aSelector
2> Normal forwarding : 实现一个完整的消息转发过程
如果Fast forwarding没有解决可以重写以下两个方法启动完整的消息的转发
+/- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
Runtime 会根据这个方法签名,创建一个NSInvocation对象(NSInvocation封装了未知消息的全部内容,
包括:方法调用者 target、方法名 selector、方法参数 argument 等),
然后调用第二个方法并将该NSInvocation对象作为参数传入。
+/- (void)forwardInvocation:(NSInvocation *)invocation
在该方法中:将未知消息转发给其它对象;改变未知消息的内容(如方法名、方法参数)再转发给其它对象;甚至可以定义任何逻辑。
⚠️如果第一个方法中没有返回方法签名,或者我们没有重写第二个方法,系统就会认为我们彻底不想处理这个消息了,
这时候就会调用以下方法
+/- (void)doesNotRecognizeSelector:(SEL)sel
方法并抛出经典的 crash:unrecognized selector sent to instance/class,结束 objc_msgSend 的全部流程。