在obj-c中我们可以向一个实例发送消息,相当于c/c++ java中的方法调用,只不过在这儿是说发送消息,实例收到消息后会进行一些处理。比如我们想调用一个方法,便向这个实例发送一个消息,实例收到消息后,如果能respondsToSelector,那么就会调用相应的方法。如果不能respond一般情况下会crash。今天要的,就是不让它crash。

首先说一下向一个实例发送一个消息后,系统是处理的流程:

1. 发送消息如:[self startwork]

2. 系统会check是否能response这个消息

3. 如果能response则调用相应方法,不能则抛出异常

在第二步中,系统是如何check实例是否能response消息呢?如果实例本身就有相应的response,那么就会相应之,如果没有系统就会发出methodSignatureForSelector消息,寻问它这个消息是否有效?有效就返回对应的方法地址之类的,无效则返回nil。如果是nil就会crash, 如果不是nil接着发送forwardInvocation消息。

所以我们在重写methodSignatureForSelector的时候就人工让其返回有效实例。  文字说不清,还是用代码说明

我们定义了这样一个类

  1. @interface TargetProxy : NSProxy {
  2. id realObject1;
  3. id realObject2;
  4. }
  5. - (id)initWithTarget1:(id)t1 target2:(id)t2;
  6. @end

实现:

  1. @implementation TargetProxy
  2. - (id)initWithTarget1:(id)t1 target2:(id)t2 {
  3. realObject1 = [t1 retain];
  4. realObject2 = [t2 retain];
  5. return self;
  6. }
  7. - (void)dealloc {
  8. [realObject1 release];
  9. [realObject2 release];
  10. [super dealloc];
  11. }
  12. // The compiler knows the types at the call site but unfortunately doesn't
  13. // leave them around for us to use, so we must poke around and find the types
  14. // so that the invocation can be initialized from the stack frame.
  15. // Here, we ask the two real objects, realObject1 first, for their method
  16. // signatures, since we'll be forwarding the message to one or the other
  17. // of them in -forwardInvocation:.  If realObject1 returns a non-nil
  18. // method signature, we use that, so in effect it has priority.
  19. - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
  20. NSMethodSignature *sig;
  21. sig = [realObject1 methodSignatureForSelector:aSelector];
  22. if (sig) return sig;
  23. sig = [realObject2 methodSignatureForSelector:aSelector];
  24. return sig;
  25. }
  26. // Invoke the invocation on whichever real object had a signature for it.
  27. - (void)forwardInvocation:(NSInvocation *)invocation {
  28. id target = [realObject1 methodSignatureForSelector:[invocation selector]] ? realObject1 : realObject2;
  29. [invocation invokeWithTarget:target];
  30. }
  31. // Override some of NSProxy's implementations to forward them...
  32. - (BOOL)respondsToSelector:(SEL)aSelector {
  33. if ([realObject1 respondsToSelector:aSelector]) return YES;
  34. if ([realObject2 respondsToSelector:aSelector]) return YES;
  35. return NO;
  36. }
  37. @end

现在我们还用这个类,注意向它发送的消息:

  1. // Create a proxy to wrap the real objects.  This is rather
  2. // artificial for the purposes of this example -- you'd rarely
  3. // have a single proxy covering two objects.  But it is possible.
  4. id proxy = [[TargetProxy alloc] initWithTarget1:string target2:array];
  5. // Note that we can't use appendFormat:, because vararg methods
  6. // cannot be forwarded!
  7. [proxy appendString:@"This "];
  8. [proxy appendString:@"is "];
  9. [proxy addObject:string];
  10. [proxy appendString:@"a "];
  11. [proxy appendString:@"test!"];
  12. NSLog(@"count should be 1, it is: %d", [proxy count]);
  13. if ([[proxy objectAtIndex:0] isEqualToString:@"This is a test!"]) {
  14. NSLog(@"Appending successful.");
  15. } else {
  16. NSLog(@"Appending failed, got: '%@'", proxy);
  17. }

运行的结果是:

count should be 1, it is:  1

Appending successful.

TargetProxy声明中是没有appendString与addObject消息的,在这儿却可以正常发送,不crash,原因就是发送消息的时候,如果原本类没有这个消息响应的时候,转向询问methodSignatureForSelector,接着在forwardInvocation将消息重定向。 上面也说了多参数的消息是不能重定向的。不过貌似要实现这个要关掉ARC。

利用forwardInvocation实现消息重定向的更多相关文章

  1. 利用System V消息队列实现回射客户/服务器

    一.介绍 在学习UNIX网络编程 卷1时,我们当时可以利用Socket套接字来实现回射客户/服务器程序,但是Socket编程是存在一些不足的,例如: 1. 服务器必须启动之时,客户端才能连上服务端,并 ...

  2. Android中利用Handler实现消息的分发机制(三)

    在第二篇文章<Android中利用Handler实现消息的分发机制(一)>中,我们讲到主线程的Looper是Android系统在启动App的时候,已经帮我们创建好了,而假设在子线程中须要去 ...

  3. 利用rabbit_mq队列消息实现对一组主机进行命令下发

    目的: 利用rabbit_mq队列消息实现对一组主机进行命令下发 server: #!/usr/bin/env python3.5 # -*- coding:utf8 -*- import os,sy ...

  4. 利用OC对象的消息重定向forwardingTargetForSelector方法构建高扩展性的滤镜功能

    在OC中,当像一个对象发送消息,而对象找到消息后,从它的类方法列表,父类方法列表,一直找到根类方法列表都没有找到与这个选择子对应的函数指针.那么这个对象就会触发消息转发机制. OC对象的继承链和isa ...

  5. 使用methodSignatureForSelector与forwardInvocation实现消息转发 (转)

    转自:http://blog.sina.com.cn/s/blog_8c87ba3b0102v006.html 在给程序添加消息转发功能以前,必须覆盖两个方法,即methodSignatureForS ...

  6. Objective-C 利用OC的消息机制,使用Method Swizzling进行方法修改

    功能:修改父类不可修改函数方法,函数方法交换 应用场景:假如我们使用的他人提供一个的framework,.m已被打包成二进制.a无法修改源码,只留下.h头文件,那假如代码中某个函数出现了问题可以通过这 ...

  7. jsp中利用response.senddirect(str)重定向,传递参数新思路

    用Servlet进行请求重定向,参数传递好办,直接用request.setAttribute(str1,str2); 但是如果不用Servlet 而是直接用jsp进行转发呢? 我们首先要知道   请求 ...

  8. Java利用Redis实现消息队列

    应用场景 为什么要用redis?二进制存储.java序列化传输.IO连接数高.连接频繁 一.序列化 这里编写了一个java序列化的工具,主要是将对象转化为byte数组,和根据byte数组反序列化成ja ...

  9. Springboot21 整合redis、利用redis实现消息队列

    1 前提准备 1.1 创建一个springboot项目 技巧01:本博文基于springboot2.0创建 1.2 安装redis 1.2.1 linux版本 参考博文 1.2.2 windows版本 ...

随机推荐

  1. 背景透明IE和rgba

    opacity:0.5; filter:Alpha(opacity=40); //IE8以下 当我们设置opacity透明时,opacity后代元素会随着一起具有透明性,所以我们Opacity中的文字 ...

  2. PAT (Advanced Level) 1079. Total Sales of Supply Chain (25)

    树的遍历. #include<cstdio> #include<cstring> #include<cmath> #include<vector> #i ...

  3. DHCP详解

    概述 DHCP(Dynamic Host Configuration Protocol,动态主机配置协议)是一个局域网的网络协议,使用UDP协议工作, 主要有两个用途:给内部网络或网络服务供应商自动分 ...

  4. GIT使用规范流程

    1:每次开发新功能时,都应该新建立一个独立的分支(branch),整个项目工程有且只有一个主分支(master branch),项目发版时是从主分支上发布. Step01:切换到主分支 $ git c ...

  5. Unity3d之协程自实现测试

    using UnityEngine; using System.Collections; public class TestStartCoroutine : MonoBehaviour { IEnum ...

  6. MODBUS协议详解

    MODBUS是一个工业上通信常用的通讯协议,一般在PLC上面用的比较多,主要是定义了一种数据传输的规范,比如数据发给谁,数据是干嘛的,数据错没错,接收到数据的从机告诉我数据有没有接受到等. 传输的方式 ...

  7. js之动态加载等待图像地址汇总

    Ajax火啊,火到了居然Loading Icons都有很多人专门提供的地步.下面是我同事给我介绍的一些提供Ajax Activity Indicators的网站,共享给大家,以便让我们的Ajax应用具 ...

  8. 12、手把手教你Extjs5(十二)执行菜单命令在tabPanel中显示模块

    上面设计好了一个模块的主界面,下面通过菜单命令的执行来把这个模块加入到主界面当中.在MainModule.js中有一个函数,生成了当前的菜单数据: // 根据data.systemMenu生成菜单条和 ...

  9. 在阿里云ECS(CentOS6.5)上安装jdk

    JDK安装 在安装前先确定服务器上没有安装过JDK 命令: java -version 结果: 查看所有java安装包 命令: yum -y list java* 结果: 选择安装所需要的JDK 命令 ...

  10. a标签屏蔽href跳转

    原文地址: http://blog.163.com/huang_qy/blog/static/615601452012101411625600/ 推荐的写法: a href="javascr ...