NSProxy学习

NSProxy学习

 NSProxyObjective-C中的基类,这个类到底是做什么的呢,有什么用呢?Apple的官方文档是这样介绍的:

NSProxy is an abstract superclassdefining an API for objects that act as stand-ins for other objects or forobjects that don’t exist yet. Typically, a message to a proxy is forwarded tothe real object or causes the proxy to load (or transform itself into) the realobject. Subclasses of NSProxy can be used to implement transparent distributedmessaging (for example, NSDistantObject) or for lazy instantiation of objects that are expensiveto create.

总的来说,NSProxy是一个虚类,你可以通过继承它,并重写以下两个方法实现消息转发的

-(void)forwardInvocation:(NSInvocation *)invocation;
-(NSMethodSignature *)methodSignatureForSelector:(SEL)sel

我们可以大体了解NSProxy主要是做什么了,我们可以使用NSProxy的消息转发机制,来转发可由其它类的对象处理的任务,达成类似多重继承的目的。

通过NSProxyObjective-C中实现多继承目的

以下是一个例子和说明:

#import <Foundation/Foundation.h>

@protocol YLHaveAMeetProtocpl <NSObject>

-(void)haveAMeetWith:(NSString *)aperson;

@end

@interface YLHaveAMeet : NSObject

@end
首先声明一个类 YLHaveAMeet,它遵守协议 YLHaveAMeetProtocpl,

#import "YLHaveAMeet.h"

@interface YLHaveAMeet()<YLHaveAMeetProtocpl>

@end

@implementation YLHaveAMeet
-(void)haveAMeetWith:(NSString *)aperson
{
    NSLog(@"开会了:%@",aperson);
}
@end

这里要注意:一定要通过protocol来声明接口,而不是直接在类的@interfere中定义。因为通过protocol来声明接口,然后让proxy类遵循此协议,可以骗过编译器防止编译器提示proxy类未声明接口的错误。这个问题下面可以看到。

 然后是另一个类YLPrepareDinner,遵守协议YLPrepareDinnerProtocol,

#import <Foundation/Foundation.h>

@protocol YLPrepareDinnerProtocol <NSObject>

-(void)haveADinner;

@end

@interface YLPrepareDinner : NSObject

@end
实现代码:

#import "YLPrepareDinner.h"

@interface YLPrepareDinner ()<YLPrepareDinnerProtocol>

@end

@implementation YLPrepareDinner

-(void)haveADinner
{
    NSLog(@"you should eat up");
}

@end

写完这两个类,我们就要用到NSProxy了。

 

#import <Foundation/Foundation.h>
#import "YLHaveAMeet.h"
#import "YLPrepareDinner.h"
@interface YLShouldDoProxy : NSProxy<YLPrepareDinnerProtocol,YLHaveAMeetProtocpl>

+(instancetype)proxy;

@end
#import "YLShouldDoProxy.h"
#import <objc/runtime.h>
@implementation YLShouldDoProxy
{
    YLHaveAMeet *_meet;
    YLPrepareDinner *_dinner;
    NSMutableDictionary *_methodsMap;
}

+(instancetype)proxy
{
    return [[YLShouldDoProxy alloc]init];
}

-(instancetype)init
{
    _methodsMap=[[NSMutableDictionary alloc]init];
    _meet=[[YLHaveAMeet alloc]init];
    _dinner=[[YLPrepareDinner alloc]init];
    [self registerMethodsWithTarget:_meet];
    [self registerMethodsWithTarget:_dinner];
    return self;
}

-(void)registerMethodsWithTarget:(id)target{
    unsigned int methodNum=0;
    Method *methodList=class_copyMethodList([target class], &methodNum);
    
    for (int i=0; i<methodNum; i++) {
        Method currentMethod=methodList[i];
        SEL currentSEL=method_getName(currentMethod);
        const char *current_method_name=sel_getName(currentSEL);
        [_methodsMap setObject:target forKey:[NSString stringWithUTF8String:current_method_name]];
    }
    free(methodList);
}

-(void)forwardInvocation:(NSInvocation *)invocation
{
    SEL sel=invocation.selector;
    NSString *methodName=NSStringFromSelector(sel);
    id target=_methodsMap[methodName];
    
    if ([target respondsToSelector:sel]&&target) {
        [invocation invokeWithTarget:target];
    }else{
        [super forwardInvocation:invocation];
    }
}

-(NSMethodSignature *)methodSignatureForSelector:(SEL)sel
{
    NSString *methodName=NSStringFromSelector(sel);
    id target=_methodsMap[methodName];
    
    if (target&&[target respondsToSelector:sel]) {
        return [target methodSignatureForSelector:sel];
    }else{
        return [super methodSignatureForSelector:sel];
    }
}

好了,我们需要做的就是把我们要做的交给NSProxy就可以了。

YLShouldDoProxy *sholdDo=[YLShouldDoProxy proxy];
[sholdDo haveAMeetWith:@"你是谁?"];
[sholdDo haveADinner];
return YES;
运行结果如下:

2017-04-17 21:06:20.034 YLProxy[18471:639293] 开会了:你是谁?

2017-04-17 21:06:20.034 YLProxy[18471:639293] you should eat up

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值