查找 IMP 的过程
来源:互联网 发布:发展环境优化月报 编辑:程序博客网 时间:2024/06/16 00:20
一、消息函数obj_msgSend:
编译器会将消息转换为对消息函数 objc_msgSend的调用,该函数有两个主要的参数:消息接收者id 和消息对应的方法选标 SEL, 同时接收消息中的任意参数:
id objc_msgSend(id theReceiver, SELtheSelector, ...)
如 [aBird fly]会被转换为如下形式的函数调用:
objc_msgSend(aBird, @selector(fly));
二、查找 IMP 的过程:
1,首先去该类的方法 cache 中查找,如果找到了就返回它;
2,如果没有找到,就去该类的方法列表中查找。如果在该类的方法列表中找到了,则将 IMP 返回,并将它加入cache中缓存起来。根据最近使用原则,这个方法再次调用的可能性很大,缓存起来可以节省下次调用再次查找的开销。
3,如果在该类的方法列表中没找到对应的 IMP,在通过该类结构中的 super_class指针在其父类结构的方法列表中去查找,直到在某个父类的方法列表中找到对应的IMP,返回它,并加入cache中;
4,如果在自身以及所有父类的方法列表中都没有找到对应的 IMP,则看是不是可以进行动态方法决议;
5,如果动态方法决议没能解决问题,进入下面要讲的消息转发流程。
当给一个对象发送它不能处理的消息的时候,就需要使用下面的两个方案了。
三、动态方法决议
Objective C 提供了一种名为动态方法决议的手段,使得我们可以在运行时动态地为一个 selector 提供实现。我们只要实现 +resolveInstanceMethod: 和/或 +resolveClassMethod: 方法,并在其中为指定的 selector 提供实现即可(通过调用运行时函数 class_addMethod 来添加)。这两个方法都是 NSObject 中的类方法,其原型为:
+(BOOL)resolveClassMethod:(SEL)sel+(BOOL)resolveInstanceMethod:(SEL)selresolveInstanceMethod 是为对象方法进行决议,而 resolveClassMethod 是为类方法进行决议。
参数 sel 是需要被动态决议的 selector;返回值文档中说是表示动态决议成功与否。如果在函数内为指定的 selector 提供实现,无论返回 YES 还是 NO,编译运行都是正确的;但如果在该函数内并不真正为 selector 提供实现,无论返回 YES 还是 NO,运行都会 crash,道理很简单,selector 并没有对应的实现,而又没有实现消息转发。
只有在 resolveInstanceMethod 的实现中没有真正为 selector 提供实现,并返回 NO 的情况下才会进入消息转发流程;否则绝不会进入消息转发流程,程序要么调用正确的动态方法,要么 crash。
如果向一个 Objective C 对象对象发送它无法处理的消息(selector),那么编译器会按照如下次序进行处理:
1,首先看是否为该 selector 提供了动态方法决议机制,如果提供了则转到 2;如果没有提供则转到 3;
2,如果动态方法决议真正为该 selector 提供了实现,那么就调用该实现,完成消息发送流程,消息转发就不会进行了;如果没有提供,则转到 3;
3,其次看是否为该 selector 提供了消息转发机制,如果提供了消息了则进行消息转发,此时,无论消息转发是怎样实现的,程序均不会 crash。(因为消息调用的控制权完全交给消息转发机制处理,即使消息转发并没有做任何事情,运行也不会有错误,编译器更不会有错误提示。);如果没提供消息转发机制,则转到 4;
4,运行报错:无法识别的 selector,程序 crash;
四、消息转发
通常,给一个对象发送它不能处理的消息会得到出错提示,然而,Objective-C运行时系统在抛出错误之前,会给消息接收对象发送一条特别的消息forwardInvocation 来通知该对象,该消息的唯一参数是个NSInvocation类型的对象——该对象封装了原始的消息和消息的参数。
我们可以实现forwardInvocation:方法来对不能处理的消息做一些默认的处理,也可以将消息转发给其他对象来处理,而不抛出错误。
forwardInvocation:消息给这个问题提供了一个更特别的,动态的解决方案:当一个对象由于没有相应的方法实现而无法响应某消息时,运行时系统将通过forwardInvocation:消息通知该对象。每个对象都从NSObject类中继承了forwardInvocation:方法。然而,NSObject中的方法实现只是简单地调用了doesNotRecognizeSelector:。通过实现我们自己的forwardInvocation:方法,我们可以在该方法实现中将消息转发给其它对象。
要转发消息给其它对象,forwardInvocation:方法所必须做的有:
1,决定将消息转发给谁,并且
2,将消息和原来的参数一块转发出去。
#pragma mark--消息转发-(void)forwardInvocation:(NSInvocation *)anInvocation{ SEL name = [anInvocation selector]; NSLog(@" >> forwardInvocation %@",NSStringFromSelector(name)); Proxy *proxy =[[Proxy alloc]init]; if ([proxy respondsToSelector:name]) { [anInvocation invokeWithTarget:proxy]; } else{ [super forwardInvocation:anInvocation]; }}-(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{ return [Proxy instanceMethodSignatureForSelector:aSelector];}
forwardInvocation:方法就像一个不能识别的消息的分发中心,将这些消息转发给不同接收对象。或者它也可以象一个运输站将所有的消息都发送给同一个接收对象。它可以将一个消息翻译成另外一个消息,或者简单的"吃掉“某些消息,因此没有响应也没有错误。forwardInvocation:方法也可以对不同的消息提供同样的响应,这一切都取决于方法的具体实现。该方法所提供是将不同的对象链接到消息链的能力。
注意: forwardInvocation:方法只有在消息接收对象中无法正常响应消息时才会被调用。 所以,如果我们希望一个对象将negotiate消息转发给其它对象,则这个对象不能有negotiate方法,也不能在动态方法决议中为之提供实现。否则,forwardInvocation:将不可能会被调用。
五、关于动态决议和消息转发同时出现的话:
//在发送一个无法识别的消息的时候,动态方法决议是先于消息转发的。//如果向一个 Objective C 对象对象发送它无法处理的消息(selector),那么编译器会按照如下次序进行处理:/** *1、首先看是否为该 selector 提供了动态方法决议机制,如果提供了则转到2;如果没有提供则转到3 *2、如果动态方法决议真正为该 selector 提供了实现,那么就调用该实现,完成消息发送流程,消息转发就不会进行了;如果没有提供,则转到 3; *3、其次看是否为该 selector 提供了消息转发机制,如果提供了消息了则进行消息转发,此时,无论消息转发是怎样实现的,程序均不会 crash。(因为消息调用的控制权完全交给消息转发机制处理,即使消息转发并没有做任何事情,运行也不会有错误,编译器更不会有错误提示。);如果没提供消息转发机制,则转到 4; *4、运行报错:无法识别的 selector,程序 crash; */
参考资料:
http://www.cppblog.com/kesalin/archive/2011/08/15/objc_message.html
http://www.cppblog.com/kesalin/archive/2012/11/14/dynamic_method_resolve.html
- 查找 IMP 的过程
- Oracle导出程序Exp/imp的使用具体过程(转)
- exp/imp造成存储过程中文乱码的原因
- tomcat查找类的过程
- sql查找过程的问题
- 动态库的查找过程
- linux 查找错误的过程
- 【EXP/IMP】EXP/IMP过程中的字符集问题
- [转]【EXP/IMP】EXP/IMP过程中的字符集问题
- EXP/IMP】EXP/IMP过程中的字符集问题
- Oracle IMP-00010、IMP-00031的解决
- Oracle IMP-00010、IMP-00031的解决
- 记一次oracle imp导入时遇到字符集告警后修改字符集的过程
- 非常纠结的查找错误的过程。
- exp/imp的Bug??
- imp/exp的使用方法
- imp exp的使用
- Delegate的IMP缓存
- VC的一些使用技巧
- liunx用户组管理
- Axis2+Rampart(WSS4J)实现UsernameToken认证方式的WS-Security(基于SOAP的Web安全调用机制)
- 1026 Table Tennis (30)完全不会
- 【Dijkstra】-HDU-2544-最短路
- 查找 IMP 的过程
- 1027 Colors in Mars (20)
- 输入三个整数,按由小到大的顺序输出
- poj 3273
- Ubuntu 12.04以上 安装搜狗输入法
- 交换两个变量的多种方法
- 八皇后问题
- pat:1002(Advanced)
- 常见音频格式