使用 NSProxy 实现消息转发

打印 上一主题 下一主题

主题 907|帖子 907|积分 2721

一、简介

​        在 iOS 应用开发中,自定义一个类一般需要继承自 NSObject 类或者 NSObject 子类,但是,NSProxy 类不是继承自 NSObject 类或者 NSObject 子类,而是一个实现了 NSObject 协议的抽象基类。
  1. /*        NSProxy.h
  2.         Copyright (c) 1994-2019, Apple Inc. All rights reserved.
  3. */
  4. #import <Foundation/NSObject.h>
  5. @class NSMethodSignature, NSInvocation;
  6. NS_ASSUME_NONNULL_BEGIN
  7. NS_ROOT_CLASS
  8. @interface NSProxy <NSObject> {
  9.     __ptrauth_objc_isa_pointer Class        isa;
  10. }
  11. + (id)alloc;
  12. + (id)allocWithZone:(nullable NSZone *)zone NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
  13. + (Class)class;
  14. - (void)forwardInvocation:(NSInvocation *)invocation;
  15. - (nullable NSMethodSignature *)methodSignatureForSelector:(SEL)sel NS_SWIFT_UNAVAILABLE("NSInvocation and related APIs not available");
  16. - (void)dealloc;
  17. - (void)finalize;
  18. @property (readonly, copy) NSString *description;
  19. @property (readonly, copy) NSString *debugDescription;
  20. + (BOOL)respondsToSelector:(SEL)aSelector;
  21. - (BOOL)allowsWeakReference API_UNAVAILABLE(macos, ios, watchos, tvos);
  22. - (BOOL)retainWeakReference API_UNAVAILABLE(macos, ios, watchos, tvos);
  23. // - (id)forwardingTargetForSelector:(SEL)aSelector;
  24. @end
  25. NS_ASSUME_NONNULL_END
复制代码
NSProxy 的作用就是作为一个委托代理对象,将消息转发给一个真实的对象或者自己加载的对象。
为了进一步了解 NSProxy 类的作用,我们来实现一个同事调用 NSMutableString 和 NSMutableArray 两个类中的方法的委托类,模拟多继承。
首先创建 TargetProxy 类,让他继承 NSProxy。并实现初始化方法。
  1. @interface TargetProxy : NSProxy
  2. /// 初始化方法,保存两个真实对象
  3. /// @param object1 第一个真实对象
  4. /// @param object2 第二个真实对象
  5. - (instancetype)initWithObject1:(id)object1 object2:(id)object2;
  6. @end
复制代码
  1. @implementation TargetProxy {
  2.     // 保存需要将消息转发到的第一个真实对象
  3.     // 第一个真实对象的方法调用优先级会比第二个真实对象的方法调用优先级高
  4.     id _realObject1;
  5.     // 保存需要将消息转发到的第二个真实对象
  6.     id _realObject2;
  7. }
  8. - (instancetype)initWithObject1:(id)object1 object2:(id)object2 {
  9.     _realObject1 = object1;
  10.     _realObject2 = object2;
  11.    
  12.     return self;
  13. }
复制代码
然后在 TargetProxy.m 文件中,重写 - methodSignatureForSelector: 获取真实对象方法签名,并重写 - forwardInvocation: 方法,调用真实的对象方法。
  1. - (NSMethodSignature *)methodSignatureForSelector:(SEL)sel {
  2.     // 获取 _realObject1 中 sel 的方法签名
  3.     NSMethodSignature *signature = [_realObject1 methodSignatureForSelector:sel];
  4.     // 如果 _realObject1 中有该方法,那么返回该方法的签名
  5.     // 如果没有,返回 _realObject1 方法签名
  6.     if (signature) {
  7.         return signature;
  8.     }
  9.     // 获取 _realObject1 中的 sel 的方法签名
  10.     signature = [_realObject2 methodSignatureForSelector:sel];
  11.     return signature;
  12. }
  13. - (void)forwardInvocation:(NSInvocation *)invocation {
  14.     // 获取拥有该方法的真实对象
  15.     id target = [_realObject1 methodSignatureForSelector:[invocation selector]] ? _realObject1 : _realObject2;
  16.     // 执行方法
  17.     [invocation invokeWithTarget:target];
  18. }
复制代码
最后,进行 Demo 测试
  1. - (void)testTargetProxy {
  2.     NSMutableString *string = [NSMutableString string];
  3.     NSMutableArray *array = [NSMutableArray array];
  4.    
  5.     id proxy = [[TargetProxy alloc] initWithObject1:string object2:array];
  6.     [proxy appendString:@"This "];
  7.     [proxy appendString:@"is "];
  8.     [proxy addObject:string];
  9.     [proxy appendString:@"a "];
  10.     [proxy appendString:@"test!"];
  11.    
  12.     NSLog(@"The string is length is: %@", [proxy valueForKey:@"length"]);
  13.     NSLog(@"count should be 1, it is %ld", [proxy count]);
  14.    
  15.     if ([[proxy objectAtIndex:0] isEqualToString:@"This is a test!"]) {
  16.         NSLog(@"Appending successful.");
  17.     } else {
  18.         NSLog(@"Appending failed,, got: '%@'", proxy);
  19.     }
  20. }
复制代码
运行上面的代码,输入日志如下:
  1. 2022-04-02 11:30:35.957145+0800 Demo[19783:586710] SuccessFully create Delegere Proxy automatically.
  2. 2022-04-02 11:30:35.959722+0800 Demo[19783:586710] The string is length is: 15
  3. 2022-04-02 11:30:35.960175+0800 Demo[19783:586710] count should be 1, it is 1
  4. 2022-04-02 11:30:40.086227+0800 Demo[19783:586710] Appending successful.
复制代码
​        以上说明,我们使用 TargetProxy 类成功的实现了消息转发。
​        当然,在大部分情况下,使用 NSObject 类也可以实现消息转发,实现方式和 NSProxy 类似,但是大部分情况下使用 NSProxy 更加合适。因为:

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

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

数据人与超自然意识

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表