1.NSProxy的定义
NSProxy is an abstract superclass defining an API for objects that act as stand-ins for other objects or for objects that don’t exist yet. 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是一个抽象的超类,它定义了一个对象的API,用来充当其他对象或者一些不存在的对象的替身。通常,发送给Proxy的消息会被转发给实际对象,或使Proxy加载(转化为)实际对象。
NSProxy的子类可以用于实现透明的分布式消息传递(例如,NSDistantObject),或者用于创建开销较大的对象的惰性实例化。
众所周知,NSObject类是Objective-C中大部分类的基类。但不是很多人知道除了NSObject之外的另一个基类——NSProxy,NSProxy实现被根类要求的基础方法,包括定义NSObject协议。然而,作为抽象类,它不实现初始化方法,并且会在收到任何它不响应的消息时引发异常。因此,具体子类必须实现一个初始化或者创建方法,并且重写- (void)forwardInvocation:(NSInvocation *)invocation;和- (nullable NSMethodSignature *)methodSignatureForSelector:(SEL)sel方法,来转发它没实现的方法。这也是NSProxy的主要功能,负责把消息转发给真正的target的代理类,NSProxy正是代理的意思。
2.NSProxy的使用
模拟多继承
多继承可以看作是单继承的扩展。所谓多继承是指派生类具有多个基类,派生类与每个基类之间的关系仍可看作是一个单继承。大家知道,Objective-C不支持多继承,但是NSProcy可以在一定程度上解决这个问题,但需要注意的是,这只是一个模拟的多继承,并不是完全的多继承。接下来,我们看一个官方的例子:
@interface TargetProxy : NSProxy { id realObject1; id realObject2; } -(id)initWithTarget1:(id)t1 target:(id)t2; @end @implementation TargetProxy -(id)initWithTarget1:(id)t1 target:(id)t2 { realObject1 = t1; realObject2 = t2; return self; } -(void)forwardInvocation:(NSInvocation *)invocation { id target = [realObject1 methodSignatureForSelector:invocation.selector]?realObject1:realObject2; [invocation invokeWithTarget:target]; } -(NSMethodSignature *)methodSignatureForSelector:(SEL)sel { NSMethodSignature *signature; signature = [realObject1 methodSignatureForSelector:sel]; if (signature) { return signature; } signature = [realObject2 methodSignatureForSelector:sel]; return signature; } -(BOOL)respondsToSelector:(SEL)aSelector { if ([realObject1 respondsToSelector:aSelector]) { return YES; } if ([realObject2 respondsToSelector:aSelector]) { return YES; } return NO; } @end 使用案例: NSMutableArray *array = [NSMutableArray array]; NSMutableString *string = [NSMutableString string]; id proxy = [[TargetProxy alloc]initWithTarget1:array target:string]; [proxy appendString:@"This "]; [proxy appendString:@"is "]; [proxy addObject:string]; [proxy appendString:@"a "]; [proxy appendString:@"test!"]; NSLog(@"count should be 1,it is:%ld",[proxy count]); if ([[proxy objectAtIndex:0] isEqualToString:@"This is a test!"]) { NSLog(@"Appending successful: %@",proxy); }else { NSLog(@"Appending failed, got: %@", proxy); } NSLog(@"Example finished without errors."); //TargetProxy拥有了NSSting与NSArray俩个类的方法属性
解决NSTimer无法释放的问题
实现两个甚至多个不同对象的消息分发
#import <Foundation/Foundation.h>
@protocol TeacherProtocol <NSObject>
- (void)beginTeachering;
@end
@interface Teacher : NSObject
@end
#import "Teacher.h"
@implementation Teacher
-(void)beginTeachering
{
NSLog(@"%s",__func__);
}
@end
#import <Foundation/Foundation.h>
@protocol StudentProtocol <NSObject>
- (void)beginLearning;
@end
@interface Student : NSObject
@end
#import "Student.h"
@implementation Student
-(void)beginLearning
{
NSLog(@"%s",__func__);
}
@end
#import <Foundation/Foundation.h>
#import "Teacher.h"
#import "Student.h"
@interface JSDistProxy : NSProxy<TeacherProtocol,StudentProtocol>
+(instancetype)sharedInstance;
-(void)registerMethodWithTarget:(id)target;
@end
#import "JSDistProxy.h"
#import <objc/runtime.h>
@interface JSDistProxy ()
@property(nonatomic,strong) NSMutableDictionary *selectorMapDic;
@end
@implementation JSDistProxy
+(instancetype)sharedInstance
{
static JSDistProxy *proxy;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
proxy = [JSDistProxy alloc];
proxy.selectorMapDic = [NSMutableDictionary dictionary];
});
return proxy;
}
-(void)registerMethodWithTarget:(id)target
{
unsigned int count = 0;
Method *methodList = class_copyMethodList([target class], &count);
for (int i=0; i<count; i++) {
Method method = methodList[i];
SEL selector = method_getName(method);
const char *method_name = sel_getName(selector);
[self.selectorMapDic setValue:target forKey:[NSString stringWithUTF8String:method_name]];
}
free(methodList);
}
-(NSMethodSignature *)methodSignatureForSelector:(SEL)sel
{
NSString *methodStr = NSStringFromSelector(sel);
if ([self.selectorMapDic.allKeys containsObject:methodStr]) {
id target = self.selectorMapDic[methodStr];
return [target methodSignatureForSelector:sel];
}
return [super methodSignatureForSelector:sel];
}
-(void)forwardInvocation:(NSInvocation *)invocation
{
NSString *methodName = NSStringFromSelector(invocation.selector);
if ([self.selectorMapDic.allKeys containsObject:methodName]) {
id target = self.selectorMapDic[methodName];
[invocation invokeWithTarget:target];
}else
{
[super forwardInvocation:invocation];
}
}
@end
使用案例:
JSDistProxy *proxy = [JSDistProxy sharedInstance];
Teacher *teacher = [Teacher new];
Student *student = [Student new];
[proxy registerMethodWithTarget:teacher];
[proxy registerMethodWithTarget:student];
[proxy beginLearning];
[proxy beginTeachering];
//实现方法的实现与声明分离,提升项目代码的可维护性,更加模块化。
参考资料: