消息转发是OC运行时比较重要的特性,Objective-C运行时的主要的任务是负责消息分发,我们在开发中"unrecognized selector sent to instance xx",实例对象没有实现对应的消息,通常我们只需要实现未实现的方法即可。一般情况我们处理一个方法,运行时寻找匹配的selector然后执行,但是有时候只想在运行时才创建某个方法,消息确没有具体的实现,这个时候就会出出现运行时错误,按照消息转发的顺序我们有三种解决办法。

动态方法处理

首先我们来看一个简单的例子,定义一个Message类,定义一个responseMethod方法,不实现方法,直接调用:

        Message  *msg=[[Message alloc]init];
[msg responseMethod];

错误信息如下:

 *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Message responseMethod]: unrecognized selector sent to instance 0x10011ad20'

动态方法的重写有两个可以调用方法:

+ (BOOL)resolveClassMethod:(SEL)sel __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
+ (BOOL)resolveInstanceMethod:(SEL)sel __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);

此时我们只需要需要重写+resolveInstanceMethod:返回YES就可以解决错误信息,注意我们需要通过class_method方法添加新的函数取代原有的sel:

+(BOOL)resolveInstanceMethod:(SEL)sel{
NSLog(@"FlyElephant-http://www.cnblogs.com/xiaofeixiang/");
if (sel==@selector(responseMethod)) {
class_addMethod([self class],sel, (IMP) dynamicMethodIMP, "v@:");
return YES;
}
return [super resolveClassMethod:sel]; }
+(BOOL)resolveClassMethod:(SEL)sel{
return [super resolveClassMethod:sel];
}

动态执行的函数:

void dynamicMethodIMP(id self, SEL _cmd)
{
NSLog(@"Developer--dynamicMethodIMP--%@",NSStringFromSelector(_cmd));
}

消息转发

如果上面的方法没有重写或者说是返回NO,那么我们接下来的按照顺序还有两种选择,两种选择的原理都是一样,消息有对应的target,我们需要更换对应的target即可:

- (id)forwardingTargetForSelector:(SEL)aSelector __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
forwardingTargetForSelector返回参数是一个对象,如果对象非nil、非self,系统会将运行的消息转发给这个对象执行,否则会执行第三种解决方案。
-(id)forwardingTargetForSelector:(SEL)aSelector{
NSLog(@"FlyElephant-http://www.cnblogs.com/xiaofeixiang/");
NSLog(@"forwardingTargetForSelector");
if (aSelector==@selector(responseMethod)) {
return developer;
}
return self;
}

第二种消息是将消息发送到另外一个对象,如果想要修改消息,那么就要使用-forwardInvocation:,运行时将消息打包成NSInvocation,然后返回给你处理。处理完之后,调用invokeWithTarget,但是如果是是调用-forwardInvocation是无法执行成功,在执行之前我们进行方法签名。

-(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{
NSLog(@"methodSignatureForSelector");
if ([super respondsToSelector:aSelector]) {
return [super methodSignatureForSelector:aSelector];
}else{
return [developer methodSignatureForSelector:aSelector];
}
} -(void)forwardInvocation:(NSInvocation *)anInvocation{
NSLog(@"forwardInvocation");
SEL sel=[anInvocation selector];
if ([developer respondsToSelector:sel]) {
[anInvocation invokeWithTarget:developer];
}else{
[super forwardInvocation:anInvocation];
}
}

关于Developer类中的方法:

@implementation Developer

-(void)responseMethod{
NSLog(@"博客园:FlyElephant-http://www.cnblogs.com/xiaofeixiang/");
NSLog(@"Developer----responseMethod");
} @end

Cocoa中代理(Proxies)和响应链(Responder Chain)用到了消息转发。NSProxy是一个轻量级的class,它的作用就是转发消息到另一个object。如果想要惰性加载object的某个属性会很有用。NSUndoManager也有用到,不过是截取消息,之后再执行,而不是转发到其他的地方。

响应链是关于Cocoa如何处理与发送事件与行为到对应的对象,通常我们处理的键盘文本框事件First Responder,如果没有处理该消息,则转发到下一个-nextResponder。这么一直下去直到找到能够处理该消息的object,或者没有找到,报错。

iOS开发-消息转发的更多相关文章

  1. iOS的消息转发机制详解

    iOS开发过程中,有一类的错误会经常遇到,就是找不到所调用的方法,当然这类问题比较好解决,给当前对象或其父类对象添加该方法即可,使得编译器在编译时能正确找到该方法:或者,还有另外的方法,由于Objec ...

  2. iOS开发——消息推送跳转

    项目开发用集成是极光推送JPush     这里主要是消息推送过来处理对应界面跳转          同时看到两篇写的不错的相关博客分享一下:      http://www.jianshu.com/ ...

  3. iOS开发-消息通知机制(NSNotification和NSNotificationCenter)

    iOS中委托模式和消息机制基本上开发中用到的比较多,一般最开始页面传值通过委托实现的比较多,类之间的传值用到的比较多,不过委托相对来说只能是一对一,比如说页面A跳转到页面B,页面的B的值改变要映射到页 ...

  4. iOS开发消息推送原理

    转载自:http://www.cnblogs.com/cdts_change/p/3240893.html 一.消息推送原理: 在实现消息推送之前先提及几个于推送相关概念,如下图1-1: 1.Prov ...

  5. 玩转iOS开发 - 消息推送

    消息推送

  6. iOS开发-消息初认识

    一.消息循环(runLoop)的作用 1,防止程序退出, 2,接受事件 3,如果没有事件,让程序自动休眠   二.消息源    1, 输入源:键盘.鼠标.NSBoard.NSPort    2,定时源 ...

  7. iOS 消息转发机制

    这篇博客的前置知识点是 OC 的消息传递机制,如果你对此还不了解,请先学习之,再来看这篇.这篇博客我尝试用口语的方式像讲述 PPT 一样给大家讲述这个知识点. 我们来思考一个问题,如果对象在收到无法解 ...

  8. iOS开发·runtime原理与实践: 消息转发篇(Message Forwarding) (消息机制,方法未实现+API不兼容奔溃,模拟多继承)...

    本文Demo传送门: MessageForwardingDemo 摘要:编程,只了解原理不行,必须实战才能知道应用场景.本系列尝试阐述runtime相关理论的同时介绍一些实战场景,而本文则是本系列的消 ...

  9. iOS开发之线程间的MachPort通信与子线程中的Notification转发

    如题,今天的博客我们就来记录一下iOS开发中使用MachPort来实现线程间的通信,然后使用该知识点来转发子线程中所发出的Notification.简单的说,MachPort的工作方式其实是将NSMa ...

随机推荐

  1. LeetCode(27): 移除元素

    Easy! 题目描述: 给定一个数组 nums 和一个值 val,你需要原地移除所有数值等于 val 的元素,返回移除后数组的新长度. 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1 ...

  2. Laravel API 限速异常 HTTPException Too Many Attemps

    最近线上 Laravel 错误日志发现了一个异常 HTTPException Too Many Attemps 而我一个同事在本地开发的过程中也频繁遇到这个异常.测试环境:Laravel 5.5. 网 ...

  3. python接口自动化测试十九:函数

    # 函数 a = [1, 3, 6, 4, 85, 32, 46]print(sum(a)) # sum,求和函数 def add(): a = 1, b = 2, return a + bprint ...

  4. linux命令: chown命令

    chown将指定文件的拥有者改为指定的用户或组,用户可以是用户名或者用户ID:组可以是组名或者组ID:文件是以空格分开的要改变权限的文件列表,支持通配符.系统管理员经常使用chown命令,在将文件拷贝 ...

  5. ERP发货系统的修改(四十三)

    产品添加批号后相应修改产品库存表中对应批次产品的数量: /// <summary> /// 产品添加批号后相应修改产品库存表中对应批次产品的数量 /// </summary> ...

  6. 【BZOJ2839】集合计数&&【BZOJ3622】已经没有什么好害怕的了

    再谈容斥原理来两道套路几乎一致的题目[BZOJ2839]集合计数Description一个有N个元素的集合有2^N个不同子集(包含空集),现在要在这2^N个集合中取出若干集合(至少一个),使得它们的交 ...

  7. BZOJ1968 [Ahoi2005]COMMON 约数研究 数论

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1968 题意概括 求 ΣF(i)   (1<=i<=n)N<=1000000 F( ...

  8. 【Java】 剑指offer(20) 表示数值的字符串

    本文参考自<剑指offer>一书,代码采用Java语言. 更多:<剑指Offer>Java实现合集   题目 请实现一个函数用来判断字符串是否表示数值(包括整数和小数).例如, ...

  9. 057 Hive项目案例过程

    1.说明 这里只粘贴一张,图,主要针对的hive的项目的实践过程. 2.图 3.需求 统计PV 统计注册人数 => 这个是一个公司会关注的,每天的注册率. 统计ip 统计跳出率 => ip ...

  10. class.forName的作用?

    调用该访问 返回一个以字符串指定类名的类的对象. 返回字节码,返回字节码的方式有几种: ①:这份字节码曾经被加载过已经存在java虚拟机中了直接返回. ②:java虚拟机中还没有这份字节码,用类加载器 ...