iOS消息转发机制

以前知道苹果执行方法是通过消息执行的,当对应的对象或者类无法处理该消息时,苹果就会启动消息转发机制,通过这一机制,我们可以告诉对象可以如何处理未知消息!

第一步:动态方法解析

对象在接收到未知的消息时,首先会调用所属类的类方法+resolveInstanceMethod:(实例方法)或者+resolveClassMethod:(类方法)。在这个方法中,我们有机会为该未知消息新增一个”处理方法”“。不过使用该方法的前提是我们已经实现了该”处理方法”,只需要在运行时通过class_addMethod函数动态添加到类里面就可以了,例如:

void clickBtn(id self,SEL _cmd){

NSLog(@"通过动态方法解析处理未知消息%@  %p",self,_cmd);

}

//消息转发第一步,可以再基类里面实现该方法,用于处理不能执行的消息

+(BOOL)resolveInstanceMethod:(SEL)sel{

//    NSString *selStr = NSStringFromSelector(sel);

//当当前实例未实现该方法时,给该实例动态添加方法。

class_addMethod(self.class, @selector(clickBtn), (IMP)clickBtn, "@:");

return [super resolveInstanceMethod:sel];

}

第二步:备用接收者

如果在上一步无法处理消息,则Runtime会继续调以下方法:

- (id)forwardingTargetForSelector:(SEL)aSelector

如果一个对象实现了这个方法,并返回一个非nil的结果,则这个对象会作为消息的新接收者,且消息会被分发到这个对象。当然这个对象不能是self自身,否则就是出现无限循环。当然,如果我们没有指定相应的对象来处理aSelector,则应该调用父类的实现来返回结果。

使用这个方法通常是在对象内部,可能还有一系列其它对象能处理该消息,我们便可借这些对象来处理消息并返回,这样在对象外部看来,还是由该对象亲自处理了这一消息。例如:

//消息转发第二步,转发给可以处理该消息的对象

-(id)forwardingTargetForSelector:(SEL)aSelector{

      BYMsgTool *mesTool = [[BYMsgTool alloc]initWithSelector:aSelector];

      return mesTool;

}

转发对象里面的实现(目前觉得这样可以统一处理无法点击的事件,设置一个专门处理无法处理消息的异常的类):

@implementation BYMsgTool

void notHaveSelector(){

NSLog(@"没有该方法");

}

-(instancetype)initWithSelector:(SEL)select{

if (self == [super init]) {

//当当前实例未实现该方法时,给该实例动态添加方法,做统一处理。

class_addMethod(self.class, select, (IMP)notHaveSelector, "@:");

}return self;

}

@end

第三步:完整消息转发

如果在上一步还不能处理未知消息,则唯一能做的就是启用完整的消息转发机制了。首先会调用- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector

这个方法返回包含方法描述信息的NSMethodSignature对象,如果找不到方法,则返回ni,则我们需要重写这个方法来返回一个合适的方法签名(就是换个对象或者类,通过该方法返回一个NSMethodSignature的对象)实例:

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {

NSLog(@"methodSignatureForSelector--%@",NSStringFromSelector(aSelector));

//实例方法返回NSMethodSignature对象

NSMethodSignature *signature = [super methodSignatureForSelector:aSelector];

if (!signature) {

if ([BYMsgTool instancesRespondToSelector:aSelector]) {

//类方法返回NSMethodSignature对象

signature = [BYMsgTool instanceMethodSignatureForSelector:aSelector];

}

}

return signature;

}

对应于实例方法,当然还有一个处理类方法的相应方法,其声明如下:

+ (NSMethodSignature *)instanceMethodSignatureForSelector:(SEL)aSelector

另外,NSObject类提供了两个方法来获取一个selector对应的方法实现的地址,如下所示:

- (IMP)methodForSelector:(SEL)aSelector

+ (IMP)instanceMethodForSelector:(SEL)aSelector

获取到了方法实现的地址,我们就可以直接将IMP以函数形式来调用。

对于methodForSelector:方法,如果接收者是一个对象,则aSelector应该是一个实例方法;如果接收者是一个类,则aSelector应该是一个类方法。

对于instanceMethodForSelector:方法,其只是向类对象索取实例方法的实现。如果接收者的实例无法响应aSelector消息,则产生一个错误。

获取到NSInvocation 对象后会调用-(void)forwardInvocation:(NSInvocation *)anInvocation方法来进行消息的完整转发,示例代码:

-(void)forwardInvocation:(NSInvocation *)anInvocation{

BYMsgTool *mesTool = [[BYMsgTool alloc]initWithSelector:anInvocation.selector];

NSLog(@"forwardInvocation--%@",NSStringFromSelector(anInvocation.selector));

if ([BYMsgTool instancesRespondToSelector:anInvocation.selector]) {

//将方法的处理者改为mesTool

[anInvocation invokeWithTarget:mesTool];

}

}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容