浅谈NSProxy

作者: _涼城 | 来源:发表于2022-04-07 09:27 被阅读0次

    什么是 NSProxy

        在苹果官方文档中是这样对 NSProxy 描述的:一个抽象的根类,通常,发送给代理的消息被转发到真实对象,或使代理加载(或转换为)真实对象。头文件代码如下:

    @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
    
    

    NSProxy 使用

        可以看到 NSProxy 是一个实现了 <NSObject> 协议的根类,NSProxy 实现根类所需的基本方法,包括 <NSObject> 协议中定义的方法。然而,作为一个抽象类,它不提供初始化方法,并且在收到任何未响应的消息时引发异常。因此,

    1. 一个具体的子类必须提供一个初始化或创建方法,
    2. 并重写 forwardInvocation:methodSignatureForSelector: 方法来处理它自己没有实现的消息。
      • forwardInvocation 的子类实现:应该执行处理调用所需的任何操作,例如通过网络转发调用或加载真实对象并将调用传递给它。
      • methodSignatureForSelector: 需要提供给定消息的参数类型信息;子类的实现应该能够确定它需要转发的消息的参数类型,并且应该相应地构造一个 NSMethodSignature 对象。

    中介者

        使用 NSProxytarget 进行消息转发,并不会对 target 造成引用关系。 A ->NSProxy -> B 。例如,YYKit/YYWeakProxy,源码如下:

    • YYWeakProxy.h

      
      /**
       A proxy used to hold a weak object.
       It can be used to avoid retain cycles, such as the target in NSTimer or CADisplayLink.
       
       sample code:
       
           @implementation MyView {
              NSTimer *_timer;
           }
           
           - (void)initTimer {
              YYWeakProxy *proxy = [YYWeakProxy proxyWithTarget:self];
              _timer = [NSTimer timerWithTimeInterval:0.1 target:proxy selector:@selector(tick:) userInfo:nil repeats:YES];
           }
           
           - (void)tick:(NSTimer *)timer {...}
           @end
       */
      @interface YYWeakProxy : NSProxy
      
      /**
       The proxy target.
       */
      @property (nullable, nonatomic, weak, readonly) id target;
      - (instancetype)initWithTarget:(id)target;
      + (instancetype)proxyWithTarget:(id)target;
      
      @end
      
    • YYWeakProxy.m

      #import "YYWeakProxy.h"
      
      
      @implementation YYWeakProxy
      
      - (instancetype)initWithTarget:(id)target {
          _target = target;
          return self;
      }
      
      + (instancetype)proxyWithTarget:(id)target {
          return [[YYWeakProxy alloc] initWithTarget:target];
      }
      
      - (id)forwardingTargetForSelector:(SEL)selector {
          return _target;
      }
      
      - (void)forwardInvocation:(NSInvocation *)invocation {
          void *null = NULL;
          [invocation setReturnValue:&null];
      }
      
      - (NSMethodSignature *)methodSignatureForSelector:(SEL)selector {
          return [NSObject instanceMethodSignatureForSelector:@selector(init)];
      }
      
      - (BOOL)respondsToSelector:(SEL)aSelector {
          return [_target respondsToSelector:aSelector];
      }
      
      - (BOOL)isEqual:(id)object {
          return [_target isEqual:object];
      }
      
      - (NSUInteger)hash {
          return [_target hash];
      }
      
      - (Class)superclass {
          return [_target superclass];
      }
      
      - (Class)class {
          return [_target class];
      }
      
      - (BOOL)isKindOfClass:(Class)aClass {
          return [_target isKindOfClass:aClass];
      }
      
      - (BOOL)isMemberOfClass:(Class)aClass {
          return [_target isMemberOfClass:aClass];
      }
      
      - (BOOL)conformsToProtocol:(Protocol *)aProtocol {
          return [_target conformsToProtocol:aProtocol];
      }
      
      - (BOOL)isProxy {
          return YES;
      }
      
      - (NSString *)description {
          return [_target description];
      }
      
      - (NSString *)debugDescription {
          return [_target debugDescription];
      }
      
      @end
      

    多继承

        NSProxy 能对多个对象方法进行转发,就使得 NSProxy 具有了多个对象的方法,可以实现“多继承”。

    相关文章

      网友评论

        本文标题:浅谈NSProxy

        本文链接:https://www.haomeiwen.com/subject/tkyjsrtx.html