NSProxy的简单使用

平时开发中我们使用的大部分类的基类都是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, NSDistantObject ) 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 NSObject  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 forwardInvocation:  and methodSignatureForSelector:  methods to handle messages that it doesn’t implement itself. A subclass’s implementation of forwardInvocation:  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. methodSignatureForSelector:  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 NSMethodSignature  object accordingly. See the NSDistantObject NSInvocation , and NSMethodSignature  class specifications for more information. 原来,它的作用是一个映射,通过定义子类,并重写

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

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

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

@protocol ProductServiceProtocel <NSObject>
- (void)getProductInfo:(NSString *)productSkn;
@end

@interface ProductService : NSObject
@end
复制代码

以及订单模块:

@protocol OrderServiceProtocel <NSObject>
- (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 <Foundation/Foundation.h>
#import "ProductService.h"
#import "OrderService.h"

@interface ServiceProxy : NSProxy <ProductServiceProtocel, OrderServiceProtocel>
+ (ServiceProxy *)shareProxy;
@end
复制代码

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

#import "ServiceProxy.h"
#import <objc/runtime.h>

@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"];
复制代码

最终的执行结果:demo

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值