您的位置:首页 > 其它

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
包装,有利于我们做更多的事情。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: