利用forwardInvocation实现消息重定向
在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的时候就人工让其返回有效实例。 文字说不清,还是用代码说明
我们定义了这样一个类
- @interface TargetProxy : NSProxy {
- id realObject1;
- id realObject2;
- }
- - (id)initWithTarget1:(id)t1 target2:(id)t2;
- @end
实现:
- @implementation TargetProxy
- - (id)initWithTarget1:(id)t1 target2:(id)t2 {
- realObject1 = [t1 retain];
- realObject2 = [t2 retain];
- return self;
- }
- - (void)dealloc {
- [realObject1 release];
- [realObject2 release];
- [super dealloc];
- }
- // The compiler knows the types at the call site but unfortunately doesn't
- // leave them around for us to use, so we must poke around and find the types
- // so that the invocation can be initialized from the stack frame.
- // Here, we ask the two real objects, realObject1 first, for their method
- // signatures, since we'll be forwarding the message to one or the other
- // of them in -forwardInvocation:. If realObject1 returns a non-nil
- // method signature, we use that, so in effect it has priority.
- - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
- NSMethodSignature *sig;
- sig = [realObject1 methodSignatureForSelector:aSelector];
- if (sig) return sig;
- sig = [realObject2 methodSignatureForSelector:aSelector];
- return sig;
- }
- // Invoke the invocation on whichever real object had a signature for it.
- - (void)forwardInvocation:(NSInvocation *)invocation {
- id target = [realObject1 methodSignatureForSelector:[invocation selector]] ? realObject1 : realObject2;
- [invocation invokeWithTarget:target];
- }
- // Override some of NSProxy's implementations to forward them...
- - (BOOL)respondsToSelector:(SEL)aSelector {
- if ([realObject1 respondsToSelector:aSelector]) return YES;
- if ([realObject2 respondsToSelector:aSelector]) return YES;
- return NO;
- }
- @end
现在我们还用这个类,注意向它发送的消息:
- // Create a proxy to wrap the real objects. This is rather
- // artificial for the purposes of this example -- you'd rarely
- // have a single proxy covering two objects. But it is possible.
- id proxy = [[TargetProxy alloc] initWithTarget1:string target2:array];
- // Note that we can't use appendFormat:, because vararg methods
- // cannot be forwarded!
- [proxy appendString:@"This "];
- [proxy appendString:@"is "];
- [proxy addObject:string];
- [proxy appendString:@"a "];
- [proxy appendString:@"test!"];
- NSLog(@"count should be 1, it is: %d", [proxy count]);
- if ([[proxy objectAtIndex:0] isEqualToString:@"This is a test!"]) {
- NSLog(@"Appending successful.");
- } else {
- NSLog(@"Appending failed, got: '%@'", proxy);
- }
运行的结果是:
count should be 1, it is: 1
Appending successful.
TargetProxy声明中是没有appendString与addObject消息的,在这儿却可以正常发送,不crash,原因就是发送消息的时候,如果原本类没有这个消息响应的时候,转向询问methodSignatureForSelector,接着在forwardInvocation将消息重定向。 上面也说了多参数的消息是不能重定向的。不过貌似要实现这个要关掉ARC。
利用forwardInvocation实现消息重定向的更多相关文章
- 利用System V消息队列实现回射客户/服务器
一.介绍 在学习UNIX网络编程 卷1时,我们当时可以利用Socket套接字来实现回射客户/服务器程序,但是Socket编程是存在一些不足的,例如: 1. 服务器必须启动之时,客户端才能连上服务端,并 ...
- Android中利用Handler实现消息的分发机制(三)
在第二篇文章<Android中利用Handler实现消息的分发机制(一)>中,我们讲到主线程的Looper是Android系统在启动App的时候,已经帮我们创建好了,而假设在子线程中须要去 ...
- 利用rabbit_mq队列消息实现对一组主机进行命令下发
目的: 利用rabbit_mq队列消息实现对一组主机进行命令下发 server: #!/usr/bin/env python3.5 # -*- coding:utf8 -*- import os,sy ...
- 利用OC对象的消息重定向forwardingTargetForSelector方法构建高扩展性的滤镜功能
在OC中,当像一个对象发送消息,而对象找到消息后,从它的类方法列表,父类方法列表,一直找到根类方法列表都没有找到与这个选择子对应的函数指针.那么这个对象就会触发消息转发机制. OC对象的继承链和isa ...
- 使用methodSignatureForSelector与forwardInvocation实现消息转发 (转)
转自:http://blog.sina.com.cn/s/blog_8c87ba3b0102v006.html 在给程序添加消息转发功能以前,必须覆盖两个方法,即methodSignatureForS ...
- Objective-C 利用OC的消息机制,使用Method Swizzling进行方法修改
功能:修改父类不可修改函数方法,函数方法交换 应用场景:假如我们使用的他人提供一个的framework,.m已被打包成二进制.a无法修改源码,只留下.h头文件,那假如代码中某个函数出现了问题可以通过这 ...
- jsp中利用response.senddirect(str)重定向,传递参数新思路
用Servlet进行请求重定向,参数传递好办,直接用request.setAttribute(str1,str2); 但是如果不用Servlet 而是直接用jsp进行转发呢? 我们首先要知道 请求 ...
- Java利用Redis实现消息队列
应用场景 为什么要用redis?二进制存储.java序列化传输.IO连接数高.连接频繁 一.序列化 这里编写了一个java序列化的工具,主要是将对象转化为byte数组,和根据byte数组反序列化成ja ...
- Springboot21 整合redis、利用redis实现消息队列
1 前提准备 1.1 创建一个springboot项目 技巧01:本博文基于springboot2.0创建 1.2 安装redis 1.2.1 linux版本 参考博文 1.2.2 windows版本 ...
随机推荐
- kindeditor集成ckplayer(带右键编辑菜单)
相信好多朋友为开源web编辑器没有集成视频播放器而烦恼,于是我就是试着修改了一下kindeditor,其实ueditor应该也是同样的,好了不多说了直接上图吧 kindeditor版本: 4.1.7 ...
- 改变cinder默认vg的方法
在存储节点:# pvcreate /dev/sdb# vgcreate vg100gb /dev/sdb # openstack-config --set /etc/cinder/cinder.con ...
- CSS中的浮动清除
先来看一个实验:现在有两个div,div身上没有任何属性.每个div中都有li,这些li都是浮动的. 理想的效果:可实际的效果: 这个地方就涉及到浮动,因为两个父元素div都没有高度(或者小于子元素的 ...
- [Asp.Net Core轻量级Aop解决方案]AspectCore Project 介绍
AspectCore Project 介绍 什么是AspectCore Project ? AspectCore Project 是适用于Asp.Net Core 平台的轻量级 Aop(Aspect- ...
- linux下文件和目录的颜色表示
蓝色表示目录: 绿色表示可执行文件: 红色表示压缩文件: 浅蓝色表示链接文件: 灰色表示其它文件: 红色闪烁表示链接的文件有问题了: 黄色是设备文件,包括block, char, fifo. (摘自: ...
- MongoDB 3.0 WiredTiger Compression and Performance
MongoDB3.0中的压缩选项 在MongoDB 3.0中,WiredTiger为集合提供三个压缩选项: 无压缩 Snappy(默认启用) – 很不错的压缩,有效利用资源 zlib(类似gzip) ...
- iOS给自定义个model排序
今天有朋友问我怎么给Model排序,我顺便写了一个,伸手党直接复制吧. 例如,我建了一个Person类,要按Person的年龄属性排序: Person *per = [[Person alloc] i ...
- MPU6050程序(转)
源:MPU6050程序 初始化定义 #ifndef _MPU6050_H #define _MPU6050_H #define PORT_USED 0 #define MPU6050_ADDRESS_ ...
- IOS开发中如何判断程序第一次启动(根据判断结果决定是否显示新手操作引导)
IOS开发中如何判断程序第一次启动 在软件下载安装完成后,第一次启动往往需要显示一个新手操作引导,来告诉用户怎么操作这个app,这就需要在程序一开始运行就判断程序是否第一次启动,如果是,则显示新手操作 ...
- IOS开发-ObjC-对象、封装
C语言是基于过程的一种编程语言,而OC语言是基于对象的一种语言. C是和其他的面向对象的语言的区别在于C语言更注重地层操作,思维方式相比面向对象的语言而言更接近机器的思维方式,而面向对象的语言更接近于 ...