RunTime:
1、获取所有的属性列表、方法列表、协议列表
2、方法交换
3、方法拦截调用,容错处理
4、动态添加方法,关联对象分类添加属性objc_setAssociatedObject
消息查找与消息转发机制:
1、从缓存方法列表中查找
2、从方法列表中查找
3、从父类指针所指对象中查找
4、一直没找到,转向拦截调用, 重定向
5、如果没有重写拦截调用的方法,程序报错
+(BOOL)resolveClassMethod:(SEL)sel;
+(BOOL)resolveInstanceMethod:(SEL)sel;
//后两个方法需要转发到其他的类处理
-(id)forwardingTargetForSelector:(SEL)aSelector;
-(void)forwardInvocation:(NSInvocation *)anInvocation;
-(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector //方法签名
调用resolveInstanceMethod:方法 (或 resolveClassMethod:)。允许用户在此时为该 Class 动态添加实现。如果有实现了,则调用并返回YES,那么重新开始objc_msgSend流程。这一次对象会响应这个选择器,一般是因为它已经调用过class_addMethod。如果仍没实现,继续下面的动作。
调用forwardingTargetForSelector:方法,尝试找到一个能响应该消息的对象。如果获取到,则直接把消息转发给它,返回非 nil 对象。否则返回 nil ,继续下面的动作。注意,这里不要返回 self ,否则会形成死循环。
调用methodSignatureForSelector:方法,尝试获得一个方法签名。如果获取不到,则直接调用doesNotRecognizeSelector抛出异常。如果能获取,则返回非nil:创建一个 NSlnvocation 并传给forwardInvocation:。
调用forwardInvocation:方法,将第3步获取到的方法签名包装成 Invocation 传入,如何处理就在这里面了,并返回非nil。
调用doesNotRecognizeSelector: ,默认的实现是抛出异常。如果第3步没能获得一个方法签名,执行该步骤。
上面前4个方法均是模板方法,开发者可以override,由 runtime 来调用。最常见的实现消息转发:就是重写方法3和4,吞掉一个消息或者代理给其他对象都是没问题的
也就是说_objc_msgForward在进行消息转发的过程中会涉及以下这几个方法:
resolveInstanceMethod:方法 (或 resolveClassMethod:)。
forwardingTargetForSelector:方法
methodSignatureForSelector:方法
forwardInvocation:方法
doesNotRecognizeSelector: 方法
网友评论