Runtime系列(消息转发)
2016-08-05 16:23
393 查看
原文来自:http://www.jianshu.com/p/4f211020de05
前言
一个方法的声明必定会有与之对应的实现,如果调用了只有声明没有实现的方法会导致程序crash,而实现并非只有中规中矩的在.m里写上相同的方法名再在内部写实现代码。正文
先来回顾一下引文中的部分内容:当调用
[receiver message]时,会触发
id objc_msgSend(id self, SEL op, ...)这个函数。
receiver通过isa指针找到当前对象的class,并在class中寻找op,如果找到,调用op,如果没找到,到super_class中继续寻找,如此循环直到NSObject(引自引文)。
如果NSObject中仍然没找到,程序并不会立即crash,而是按照优先级执行下列三个方法(下列方法优先级依次递减,高优先级方法消息转发成功不会再执行低优先级方法):
1.+ resolveInstanceMethod:(SEL)sel // 对应实例方法 + resolveClassMethod:(SEL)sel // 对应类方法 2.- (id)forwardingTargetForSelector:(SEL)aSelector 3.- (void)forwardInvocation:(NSInvocation *)anInvocation
举例
比如在ViewController.h中声明,并且不在ViewController.m中直接实现,如何确保程序正常运行
@interface ViewController : UIViewController - (void)sayHello:(NSString *)name; @end
resolveInstanceMethod:
以实例方法为例:
resolveInstanceMethod 1.png
说一下这个函数
class_addMethod(<#__unsafe_unretained Class cls#>, <#SEL name#>, <#IMP imp#>, <#const char *types#>)
cls表示要添加方法的类,
name表示要添加方法的
SEL,
imp表示要添加方法的
IMP,
types表要添加方法的返回值和参数类型。
上篇文章已经说过
SEL和
IMP的异同,也许你会想这里的
name和
imp参数是否重复,毕竟
receiver已经明确,无论通过
SEL还是
IMP都是可以找到对应函数\方法的。正常情况是这样,但是这里只有声明没有常规的实现,如果只有
SEL会导致找不到入口,如果只有
IMP会导致函数\方法名不确定。
示例中
type的值为
v@:@,如果不用
imp_implementationWithBlock来写可能更好理解
resolveInstanceMethod 2.png
v@:@中:
v对应着返回值
void,
第一个@对应着第一个参数类型
id,
:对应着第二个参数类型
SEL,
第二个@对应着三个参数类型
NSString关于Type Encodings可参考官方文档
forwardingTargetForSelector:
forwardingTargetForSelector.png
Message.h.png
Messsage.m.png
将ViewController中调用的实例方法转移到Message中,这里很好理解无须赘述。
forwardInvocation:
forwardInvocation.png
同样,这里是将ViewController中调用的实例方法转移到Message中,只是多了一层
NSInvocation包装,有利于我们做更多的事情。
相关文章推荐
- Gym 100818F Irrational Roots
- 给定一个链表,链表的每一个节点包含三个属性:1、节点值;2、指向下一个结点的引用;3、随机指向链表内任意一个节点的引用,也能不指向任何节点。复制该链表
- Hive中小表与大表关联(join)的性能分析
- PTAM学习笔记(一)---PTAM在windows上的编译
- 趣味问题——提灯过桥问题
- 几个性能测试工具
- UDP广域网,局域网通信-原理分析,穿透技术
- iOS判断是否插入耳机
- STL中set容器的一点总结
- Runtime系列(Method Swizzling)
- 拓扑排序
- 排序算法总结(三)选择排序【Select Sort】
- SSH学习之Hibernate session的方法全集
- leetcode single number系列
- js写的5秒钟倒计时跳转
- bzoj3670 noi2014动物园(kmp)
- 由于系统缓冲区空间不足或队列已满,不能执行套接字上的操作
- js实现精确到毫秒的倒计时效果
- resource
- Linux驱动开发 -- 打开dev_dbg()