iOS的消息转发机制
这里讲的是消息转发机制,如果对象收到无法解读的消息之后会发生什么情况?
我们都知道Objective-c是谁一种动态语言,我们说App运行它要经历两个过程,分别说编译阶段和运行阶段。编译阶段编译器只会判断程序中有没有这个方法,而不会去十分准确的去判断这个方法是否属于调用的对象。如图1
在编译阶段,编译器对无法解读的方法无法确定对错,毕竟我们都知道我们可以动态的给对象增加方法,当对象接受到无法解读的方法后,就会启动“消息转发(messafe forwarding)”机制,程序经由此过程告诉对象应该如何处理未知消息<这段话来自effective Object - C 2.0>
消息转发流程
图1:消息转发流程图图片来源于:
http://www.cnblogs.com/ansyxpf/p/5690215.html
要点:
- 1.越到后面消息处理所消耗的资源越大,最好能在第一步就完成,这样的话运行期间就会将方法缓存起来
- 2.注意,这个消息转发流程是,当当前类到基类整个过程都没有找个这个方法的时候才会调用消息循环。
+ 3.通过流程图我们可以看出,我们可以在任何一个步骤动态的给期添加方法属性让方法执行,也可以不做处理让程序不carsh
+ (BOOL)resolveInstanceMethod:(SEL)sel
在SMPerson.m方法里面实现这个方法并打印
<pre>
//#import "SMPerson.h"
@implementation SMPerson
// 不让它生成setter和getter方法
@dynamic name;
+
(BOOL)resolveInstanceMethod:(SEL)sel {
NSLog(@"%s",func);
return [super resolveInstanceMethod:sel];
}
@end
// 是为了好看,复制的时候可以去掉
</pre>
当启动消息转发机制,首先会到<code>+ (BOOL)resolveInstanceMethod:(SEL)sel</code>它是动态给选择器提供一个实现,如果它返回YES,那么会有对这个方法处理的对象,如果返回NO,将跳到下一个消息,去寻找这个方法的处理者。
<code>所以为了让我们的方法得到处理我们可以通过运行时动态给他添加方法</code>
在这个方法动态添加方法
我们都知道,出现的问题是,我们调用的这个setName方法,不存在,那么问题就好解决了,我们添加一个这个方法就好了
<pre>
-
(BOOL)resolveInstanceMethod:(SEL)sel {
NSString *selStr = NSStringFromSelector(sel);
// 如果是set方法
if ([selStr hasPrefix:@"set"]) {/** 第一个参数: 填入当前方法 第二个参数: 要执行的方法名称 第三个参数: 这个类调用的C语言方法 第四个参数: 方法的形式 */ class_addMethod([self class], sel, (IMP)AutoDictionarySetter,"v@:@"); return YES;
} else { // 如果它不是setter方法这里默认就认为是getter方法
// 增加getter方法
class_addMethod([self class], sel, (IMP)AutoDictionarygetter, "@@:");
return YES;
}
return NO;
}
</pre>
setter 方法 和getter方法添加的c语言实现
<pre>
void AutoDictionarySetter(id self, SEL _cmd, id vaule) {
NSString *selStr = NSStringFromSelector(_cmd);
// 消除set方法的点和set
NSMutableString *key = [selStr mutableCopy];
[key deleteCharactersInRange:NSMakeRange(key.length - 1, 1)];
[key deleteCharactersInRange:NSMakeRange(0, 3)];
// 让它变成小些
NSString *lowSrr = [[key substringFromIndex:0] lowercaseString];
[key replaceCharactersInRange:NSMakeRange(0, 1) withString:lowSrr];
if (vaule) {
[dictStore setValue:vaule forKey:key];
}else {
[dictStore removeObjectForKey:key];
}
}
id AutoDictionarygetter(id self, SEL _cmd) {
NSString *key = NSStringFromSelector(_cmd);
return [dictStore objectForKey:key];
}
</pre>
当我们给当前类动态的补充了这个方法,然后返回YES ,根据图1消息转发所示 返回YES,消息已经被处理,当返回NO的时候呢?
备缓接受者
上面提到,当<code> resolveInstanceMethod </code>接收不到数据的时候,