一、简介

​ 在 iOS 应用开发中,自定义一个类一般需要继承自 NSObject 类或者 NSObject 子类,但是,NSProxy 类不是继承自 NSObject 类或者 NSObject 子类,而是一个实现了 NSObject 协议的抽象基类。

/*	NSProxy.h
Copyright (c) 1994-2019, Apple Inc. All rights reserved.
*/ #import <Foundation/NSObject.h> @class NSMethodSignature, NSInvocation; NS_ASSUME_NONNULL_BEGIN NS_ROOT_CLASS
@interface NSProxy <NSObject> {
__ptrauth_objc_isa_pointer Class isa;
} + (id)alloc;
+ (id)allocWithZone:(nullable NSZone *)zone NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
+ (Class)class; - (void)forwardInvocation:(NSInvocation *)invocation;
- (nullable NSMethodSignature *)methodSignatureForSelector:(SEL)sel NS_SWIFT_UNAVAILABLE("NSInvocation and related APIs not available");
- (void)dealloc;
- (void)finalize;
@property (readonly, copy) NSString *description;
@property (readonly, copy) NSString *debugDescription;
+ (BOOL)respondsToSelector:(SEL)aSelector; - (BOOL)allowsWeakReference API_UNAVAILABLE(macos, ios, watchos, tvos);
- (BOOL)retainWeakReference API_UNAVAILABLE(macos, ios, watchos, tvos); // - (id)forwardingTargetForSelector:(SEL)aSelector; @end NS_ASSUME_NONNULL_END

NSProxy 的作用就是作为一个委托代理对象,将消息转发给一个真实的对象或者自己加载的对象。

为了进一步了解 NSProxy 类的作用,我们来实现一个同事调用 NSMutableString 和 NSMutableArray 两个类中的方法的委托类,模拟多继承。

首先创建 TargetProxy 类,让他继承 NSProxy。并实现初始化方法。

@interface TargetProxy : NSProxy

/// 初始化方法,保存两个真实对象
/// @param object1 第一个真实对象
/// @param object2 第二个真实对象
- (instancetype)initWithObject1:(id)object1 object2:(id)object2; @end
@implementation TargetProxy {

    // 保存需要将消息转发到的第一个真实对象
// 第一个真实对象的方法调用优先级会比第二个真实对象的方法调用优先级高
id _realObject1;
// 保存需要将消息转发到的第二个真实对象
id _realObject2;
} - (instancetype)initWithObject1:(id)object1 object2:(id)object2 {
_realObject1 = object1;
_realObject2 = object2; return self;
}

然后在 TargetProxy.m 文件中,重写 - methodSignatureForSelector: 获取真实对象方法签名,并重写 - forwardInvocation: 方法,调用真实的对象方法。

- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel {
// 获取 _realObject1 中 sel 的方法签名
NSMethodSignature *signature = [_realObject1 methodSignatureForSelector:sel];
// 如果 _realObject1 中有该方法,那么返回该方法的签名
// 如果没有,返回 _realObject1 方法签名
if (signature) {
return signature;
}
// 获取 _realObject1 中的 sel 的方法签名
signature = [_realObject2 methodSignatureForSelector:sel];
return signature;
} - (void)forwardInvocation:(NSInvocation *)invocation {
// 获取拥有该方法的真实对象
id target = [_realObject1 methodSignatureForSelector:[invocation selector]] ? _realObject1 : _realObject2; // 执行方法
[invocation invokeWithTarget:target];
}

最后,进行 Demo 测试

- (void)testTargetProxy {
NSMutableString *string = [NSMutableString string];
NSMutableArray *array = [NSMutableArray array]; id proxy = [[TargetProxy alloc] initWithObject1:string object2:array];
[proxy appendString:@"This "];
[proxy appendString:@"is "];
[proxy addObject:string];
[proxy appendString:@"a "];
[proxy appendString:@"test!"]; NSLog(@"The string is length is: %@", [proxy valueForKey:@"length"]);
NSLog(@"count should be 1, it is %ld", [proxy count]); if ([[proxy objectAtIndex:0] isEqualToString:@"This is a test!"]) {
NSLog(@"Appending successful.");
} else {
NSLog(@"Appending failed,, got: '%@'", proxy);
}
}

运行上面的代码,输入日志如下:

2022-04-02 11:30:35.957145+0800 Demo[19783:586710] SuccessFully create Delegere Proxy automatically.
2022-04-02 11:30:35.959722+0800 Demo[19783:586710] The string is length is: 15
2022-04-02 11:30:35.960175+0800 Demo[19783:586710] count should be 1, it is 1
2022-04-02 11:30:40.086227+0800 Demo[19783:586710] Appending successful.

​ 以上说明,我们使用 TargetProxy 类成功的实现了消息转发。

​ 当然,在大部分情况下,使用 NSObject 类也可以实现消息转发,实现方式和 NSProxy 类似,但是大部分情况下使用 NSProxy 更加合适。因为:

  • NSProxy 类实现了包括 NSObject 协议在内基类所需的基础方法
  • 通过 NSObject 类实现的代理类不会自动的转发 NSObject 协议中的方法
  • 通过 NSObject 类实现的代理类不会自动的转发 NSObject 类别中的方法

最新文章

  1. AS3绘制扇形算法解析
  2. MySQL解决插入emoji表情失败的问题
  3. (圆形imageview 类似qq头像)---》(ps:引用第三库APAvatarImageView&gt;
  4. mybatis(1):入坑篇
  5. MKServerBuilder.psd1
  6. 一次优化web项目的经历记录(三)
  7. SQL - 复制数据库中的一行
  8. swift和oc混编
  9. Ext 怎么发ajax请求
  10. centos虚拟机初始化脚本
  11. CSS预编译器less简单用法
  12. [DeeplearningAI笔记]改善深层神经网络_优化算法2.1_2.2_mini-batch梯度下降法
  13. vue 点击当前元素添加class 去掉兄弟的class 获取当前点击元素的文字
  14. LWIP之ARP协议
  15. SQL Server查询优化器的工作原理
  16. Nowcoder | [题解-N189]牛客OI赛制测试赛3
  17. 解决mysql中文乱码问题?
  18. 编译64位cu文件的设置
  19. 【Hadoop】搭建完全分布式的hadoop【转】
  20. Oauth2.0(六):Resource Owner Password Credentials 授权和 Client Credentials 授权

热门文章

  1. python基础练习题(题目 统计 1 到 100 之和)
  2. 你不知道的下划线属性-text-decoration
  3. 给swap分区扩容
  4. 基础知识:CERT内部威胁定义以及四大原因
  5. [没接触过kubevirt?]15分钟快速入门kubevirt
  6. NLP教程(6) - 神经机器翻译、seq2seq与注意力机制
  7. 机器学习实战-k近邻算法
  8. Java课程课堂作业代码
  9. 108_Power Pivot购物篮分析分组GENERATE之笛卡尔积、排列、组合
  10. veeambackup通过虚拟机还原系统文件操作说明