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的使用

  1. 模拟多继承

    多继承可以看作是单继承的扩展。所谓多继承是指派生类具有多个基类,派生类与每个基类之间的关系仍可看作是一个单继承。大家知道,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俩个类的方法属性复制代码
  2. 解决NSTimer无法释放的问题

    解决NSTimer的内存泄漏问题

  3. 实现两个甚至多个不同对象的消息分发

#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];//实现方法的实现与声明分离,提升项目代码的可维护性,更加模块化。
复制代码

参考资料:

关于NSProxy的理解

NSProxy——少见却神奇的类

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

NSProxy的理解和使用相关推荐

  1. iOS NSProxy 的简单介绍和使用

    1.首先简单说一下OC消息发送机制 消息发送分两步: 第一步,编译阶段 不带参数:objc_msgSend(receiver,selector) 带参数:objc_msgSend(recevier,s ...

  2. linux container容器技术框架性理解

    我对container原理的一些理解(基于linux kernel 2.6.38) by kin 2011.04.17 ======================================== ...

  3. 深入理解 Linux 内核

    Linux 内核系列文章 Linux 内核设计与实现 深入理解 Linux 内核 深入理解 Linux 内核(二) Linux 设备驱动程序 Linux设备驱动开发详解 文章目录 Linux 内核系列 ...

  4. [iOS]-NSTimer与循环引用的理解

    目录: 参考的博客: 问题引入 循环引用 简单的循环引用 Block中的循环引用强弱共舞 Delegate中的循环引用 NSTimer 创建NSTimer 销毁NSTimer invalidate f ...

  5. 通用解题法——回溯算法(理解+练习)

    积累算法经验,积累解题方法--回溯算法,你必须要掌握的解题方法! 什么是回溯算法呢? 回溯算法实际上一个类似枚举的搜索尝试过程,主要是在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时,就&quo ...

  6. stream流对象的理解及使用

    我的理解:用stream流式处理数据,将数据用一个一个方法去 . (点,即调用) 得到新的数据结果,可以一步达成. 有多种方式生成 Stream Source: 从 Collection 和数组 Co ...

  7. Linux shell 学习笔记(11)— 理解输入和输出(标准输入、输出、错误以及临时重定向和永久重定向)

    1. 理解输入和输出 1.1 标准文件描述符 Linux 系统将每个对象当作文件处理.这包括输入和输出进程.Linux 用文件描述符(file descriptor)来标识每个文件对象.文件描述符是一 ...

  8. java局部变量全局变量,实例变量的理解

    java局部变量全局变量,实例变量的理解 局部变量 可以理解为写在方法中的变量. public class Variable {//类变量static String name = "小明&q ...

  9. 智能文档理解:通用文档预训练模型

    预训练模型到底是什么,它是如何被应用在产品里,未来又有哪些机会和挑战? 预训练模型把迁移学习很好地用起来了,让我们感到眼前一亮.这和小孩子读书一样,一开始语文.数学.化学都学,读书.网上游戏等,在脑子 ...

最新文章

  1. dubbo 扩展单例的保存
  2. petalinux 下使用 xsa 查看所有的 Zynq Reg 设置
  3. oracle对sga统计信息不对,关于oracle sga设置的总结,很经典--转
  4. java并发:简单面试问题集锦
  5. .DLL文件是什么?
  6. PowerShell 调用dll
  7. 【Python之旅】第二篇(二):列表与元组
  8. python分数由高至低排序_python之数据库
  9. pytnon 学习day-1
  10. 优课计算机考试,新生入学安全教育考试之优课操作流程
  11. 计算机自动设置开机,电脑定时开机怎么设置?电脑设置每天自动开机
  12. 无线摄像头如何连接服务器,网络摄像头怎样连接到云服务器
  13. 教你如何上×××钱:轻松挂机,在家月入千\\万!$
  14. SMT32同步采样ADC芯片ADS8329 | 立创开源
  15. 2019阿里巴巴技术面试题集锦!(附答案)
  16. 跳马周游c++_NOIP信息学奥赛C++视频教程
  17. 2022-2028全球公关公司行业调研及趋势分析报告
  18. 日语基础学习 Day 09
  19. 记录使用nginx部署静态资源流程,以及遇到的访问静态资源404问题
  20. Android App开发实战项目之购物车(附源码 超详细必看)

热门文章

  1. Atitit.安全性方案规划设计4gm  v1 q928
  2. FreeBSD下查看各软件版本命令
  3. 给你的开源项目加一个绶带吧
  4. applicationContext.xml 的位置问题
  5. 【pyQuery】抓取startup news首页
  6. 【转】C++的面象对象总结
  7. 关于JAVA的参数列表传值的问题
  8. oracle教程之DML事务锁定的机制
  9. 动态性能视图v$lock访问很慢的解决办法
  10. c# winform listview 删除