使用 NSProxy 实现消息转发
一、简介
在 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 类别中的方法
使用 NSProxy 实现消息转发的更多相关文章
- iOS 消息转发以及 NSProxy 实战
最后更新: 2018-01-17 一.消息派发机制-NSObject 在 iOS 开发中, 调用对象的方法就是给对象发送一个消息.了解消息的派发机制对于iOS开发来说是一个很实用且强大的工具, 下面我 ...
- iOS开发-消息转发
消息转发是OC运行时比较重要的特性,Objective-C运行时的主要的任务是负责消息分发,我们在开发中"unrecognized selector sent to instance xx& ...
- runtime消息转发机制
Objective-C 扩展了 C 语言,并加入了面向对象特性和 Smalltalk 式的消息传递机制.而这个扩展的核心是一个用 C 和 编译语言 写的 Runtime 库.它是 Objective- ...
- iOS - 消息转发处理
详细运行时基础 NSInvocation介绍 NSHipster-Swizzling Objective-C Method相关方法分析 Type Encodings Objc是OOP,所以有多态. 当 ...
- iOS 消息转发机制
这篇博客的前置知识点是 OC 的消息传递机制,如果你对此还不了解,请先学习之,再来看这篇.这篇博客我尝试用口语的方式像讲述 PPT 一样给大家讲述这个知识点. 我们来思考一个问题,如果对象在收到无法解 ...
- ios 消息转发初探
有时候服务器的接口文档上一个数据写的是string类型,这时候你就会直接把它赋值给一个label. 问题来了,有时候这个string的确是string,没有问题,有时候又是NSNumber,当然不管三 ...
- Effective Objective-C 2.0 — 第12条:理解消息转发机制
11 条讲解了对象的消息传递机制 12条讲解对象在收到无法解读的消息之后会发生什么,就会启动“消息转发”(message forwarding)机制, 若对象无法响应某个选择子,则进入消息转发流程. ...
- runtime之消息转发
前言 在上一篇文章中我们初尝了runtime的黑魔法,可以在程序编译阶段就获取到成员变量的名字,特性以及动态的给对象增加属性等等,在接下来中我们进一步了解OC的消息发送机制.如果之前没接触过runti ...
- iOS 消息转发
消息转发 delegate和protocol 类别 消息转发 当向someObject发送某消息,但runtime system在当前类和父类中都找不到对应方法的实现时,runt ...
随机推荐
- Flex 的 多种对齐属性
1. html 结构 <div id="container"> <div class="item item-1"> <h3> ...
- 【论文笔记】A review of applications in federated learning(综述)
A review of applications in federated learning Authors Li Li, Yuxi Fan, Mike Tse, Kuo-Yi Lin Keyword ...
- Apollo的docker配置详解步骤
Apollo 的docker配置 基础环境 centOS7 + Docker服务 + mysql服务 1. 下载Apollo的包 git clone https://github.com/ctripc ...
- JS中的 && 、|| 、??、?. 运算符
javascript有不少好用的运算符,合理的使用可以大大提高工作效率,以下简单介绍了4种,具体如下: && 逻辑与运算(&&)是 AND 布尔操作.只有两个操作数都为 ...
- 项目文章|DNA(羟)甲基化研究揭示铁离子依赖表观调控促进狼疮致病性T细胞分化|易基因
易基因(羟)甲基化DNA免疫共沉淀测序(h)MeDIP-seq研究成果见刊<Journal of Clinical Investigation> 2022年5月2日,中南大学湘雅二医院赵明 ...
- Oracle19c单实例数据库配置OGG单用户数据同步测试
目录 19c单实例配置GoldenGate 并进行用户数据同步测试 一.数据库操作 1.开启数据库附加日志 2.开启数据库归档模式 3.开启goldengate同步 4.创建goldengate管理用 ...
- kali linux安装后乱码的解决方法
操作系统是5.3 解决方法是在终端执行命令: sudo apt-get install ttf-wqy-zenhei
- 服务器/网络/虚拟化/云平台自动化运维-ansible
ansible与netconf的对比 首先明确一个概念,netconf是协议,ansible是python编写的工具 netconf 使用YANG建模,XML进行数据填充,使用netconf协议进行传 ...
- nodejs + koa + typescript 集成和自动重启
版本说明 Node.js: 16.13.1 全局安装 TypeScript yarn global add typescript 创建项目 创建如下目录结构 project ├── src │ └── ...
- 【数据库】MYSQL如何添加索引
1.使用ALTER TABLE语句创建索性 应用于表创建完毕之后再添加. 1.1语法 ALTER TABLE 表名 ADD 索引类型 (unique,primary key,fulltext,inde ...