博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
NSProxy的简单使用
阅读量:7115 次
发布时间:2019-06-28

本文共 4630 字,大约阅读时间需要 15 分钟。

平时开发中我们使用的大部分类的基类都是NSObject,今天介绍另一个基类——NSProxy。 先来看一下苹果官方文档: ##NSProxy An abstract superclass defining an API for objects that act as stand-ins for other objects or for objects that don’t exist yet. 好的,我们知道了他是一个抽象类。 再往下 ##Overview Typically, a message to a proxy is forwarded to the real object or causes the proxy to load (or transform itself into) the real object. Subclasses of NSProxy  can be used to implement transparent distributed messaging (for example, ) or for lazy instantiation of objects that are expensive to create. NSProxy  implements the basic methods required of a root class, including those defined in the  protocol. However, as an abstract class it doesn’t provide an initialization method, and it raises an exception upon receiving any message it doesn’t respond to. A concrete subclass must therefore provide an initialization or creation method and override the  and  methods to handle messages that it doesn’t implement itself. A subclass’s implementation of  should do whatever is needed to process the invocation, such as forwarding the invocation over the network or loading the real object and passing it the invocation.  is required to provide argument type information for a given message; a subclass’s implementation should be able to determine the argument types for the messages it needs to forward and should construct an  object accordingly. See the , , and  class specifications for more information. 原来,它的作用是一个映射,通过定义子类,并重写

- (void)forwardInvocation:(NSInvocation *)anInvocation;- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel;复制代码

这两个方法来实现将消息转发给真正的对象。我们知道OC不支持多继承,通过NSProxy,就可以模拟实现多继承。那么现在,NSProxy怎么用呢?

假设现在有这样一个需求: 我们已经将项目中的网络接口进行了模块化,将不同模块下的接口放在了不同的文件中。当我们想调用不同模块下的接口时,想要通过一个统一的映射来调用,现在我们来写这个映射。 首先,我们来创建两个接口模块。 商品模块:

@protocol ProductServiceProtocel 
- (void)getProductInfo:(NSString *)productSkn;@end@interface ProductService : NSObject@end复制代码

以及订单模块:

@protocol OrderServiceProtocel 
- (void)submitOrder:(NSString *)prodcutName;@end@interface OrderService : NSObject@end复制代码

######注意:这里的接口声明要写在protocol中,然后让我们的proxy遵循这两个协议,用来骗过编译器。 然后我们实现这两个接口模块:

@implementation ProductService- (void)getProductInfo:(NSString *)productSkn {    NSLog(@"我是一件程序员标配的横条纹T,我的skn是%@",productSkn);}@end复制代码
@implementation OrderService- (void)submitOrder:(NSString *)prodcutName {    NSLog(@"我买了一件%@",prodcutName);}@end复制代码

现在我们来写我们的映射。

#import 
#import "ProductService.h"#import "OrderService.h"@interface ServiceProxy : NSProxy
+ (ServiceProxy *)shareProxy;@end复制代码

NSProxy是一个抽象类,系统不提供init方法,所以需要我们自己实现。

#import "ServiceProxy.h"#import 
@implementation ServiceProxy{ ProductService *_product; OrderService *_order; NSMutableDictionary *_targetProxy;}#pragma class method+ (ServiceProxy *)shareProxy { return [[ServiceProxy alloc] init];}#pragma init- (ServiceProxy *)init { _targetProxy = [NSMutableDictionary dictionary]; _product = [[ProductService alloc] init]; _order = [[OrderService alloc] init]; [self _registerMethodsWithTarget:_product]; [self _registerMethodsWithTarget:_order]; return self;}复制代码

在init方法中,初始化成员变量已经将各接口模块中的方法以及对象映射在一个字典中。

#pragma private- (void)_registerMethodsWithTarget:(id)target {    unsigned int methodsNum = 0;        Method *methodList = class_copyMethodList([target class], &methodsNum);    for (int i = 0; i < methodsNum; i++) {        Method method = methodList[i];        SEL temp_sel = method_getName(method);        const char *temp_method_name = sel_getName(temp_sel);        [_targetProxy setObject:target forKey:[NSString stringWithUTF8String:temp_method_name]];    }        free(methodList);}复制代码

接下来就可以重写系统提供的两个方法,根据方法名从我们的映射字典中找到对应的target,然后执行。

#pragma override- (void)forwardInvocation:(NSInvocation *)invocation {    SEL selector = invocation.selector;    NSString *methodName = NSStringFromSelector(selector);    id target = _targetProxy[methodName];    if (target && [target respondsToSelector:selector]) {        [invocation invokeWithTarget:target];    }else {        [super forwardInvocation:invocation];    }}- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel {    NSString *methodName = NSStringFromSelector(sel);    id target = _targetProxy[methodName];    if (target && [target respondsToSelector:sel]) {        return [target methodSignatureForSelector:sel];    }else {        return [super methodSignatureForSelector:sel];    }}复制代码

现在服务映射就写完了,在控制器中来调动接口:

ServiceProxy *proxy = [ServiceProxy shareProxy];[proxy getProductInfo:@"123456"];[proxy submitOrder:@"程序员标配的横条纹T"];复制代码

最终的执行结果:

转载于:https://juejin.im/post/5a333431f265da43176a2e75

你可能感兴趣的文章
单IP无TMG拓扑Lync Server 2013:活动目录
查看>>
3.VMware vsphere 5.0新体验-安装VMware Center
查看>>
趣题: 一道面试题的解法
查看>>
Java Scoket之java.io.EOFException解决方案
查看>>
Oracle分析函数四——函数RANK,DENSE_RANK,FIRST,LAST…
查看>>
Android应用程序启动过程源代码分析(5)
查看>>
选择目录对话框和选择文件对话框
查看>>
Linux桌面版横评:八、中标普华桌面Linux 3.0.1
查看>>
《统一沟通-微软-实战》-6-部署-2-中介服务器-2-安装中介服务器
查看>>
.net中窗体之间的数据交换总结
查看>>
SystemCenter2012SP1实践(13)虚拟存储的配置
查看>>
一段实现HTML页面内定期触发事件的JavaScript代码
查看>>
支持多核smp squid3.2 缓存反向代理【ok】~
查看>>
[CTO札记]:User与Content的关系
查看>>
让UpdatePanel支持文件上传(5):支持页面重定向的HttpModule
查看>>
Java线程:新特征-阻塞栈
查看>>
CentOS 5.5升级内核到2.6.35.4
查看>>
查询整个数据库中某个特定值所在的表和字段的方法
查看>>
JS把数组中相同元素组合成一个新的数组问题
查看>>
《Linux内核设计与实现》读书笔记(三)- Linux的进程
查看>>