NSProxy使用

3,497 阅读2分钟

首先展示一个NSProxy使用的例子。

NSProxy使用示例

@interface BDWeakProxy : NSProxy

@property (nonatomic, weak) id target;

@end

@implementation BDWeakProxy

- (instancetype)initWithTarget:(id)target {
    self.target = target;
    return self;
}

- (void)forwardInvocation:(NSInvocation *)invocation {
    [invocation invokeWithTarget:self.target];
}

- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel {
    return [self.target methodSignatureForSelector:sel];
}

@end

根据官方文档,通过重写这两个方法,就可以利用BDWeakProxy来进行消息转发到target

但是如果用NSObject实现呢?

@interface BDWeakProxy : NSObject

@property (nonatomic, weak) id target;

@end

@implementation BDWeakProxy

- (instancetype)initWithTarget:(id)target {
	self = [super init];
    if (self) {
        self.target = target;
    }
    return self;
}

- (void)forwardInvocation:(NSInvocation *)invocation {
    [invocation invokeWithTarget:self.target];
}

- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel {
    return [self.target methodSignatureForSelector:sel];
}

@end

同样可以做到消息转发,这两个又有什么区别呢?

NSProxy不同之处

  1. NSProxy类是没有init方法的
  2. NSProxy是一个抽象类,且父类不是NSObject
  3. 一些NSObject有的方法NSProxy没有实现
  4. NSProxy的消息转发机制

下面展示一下一般对象的消息转发机制。

oc.png

消息转发机制这个就不用解释了,上面两个例子最终转发都是利用了消息转发机制,到最后一步实现消息转发到target。

这篇文章中提说,通过继承自NSObject的代理类是不会自动转发respondsToSelector:和isKindOfClass:这两个方法的, 而继承自NSProxy的代理类却是可以的. 测试中定义的其它接口二者表现都是一致的.

实际原因:

  1. NSProxy没有实现respondsToSelector:isKindOfClass: 这两个方法,故而转发。
  2. NSObject有实现。

NSProxy的消息转发机制

其实重点在于NSProxy的方法。

NS_ROOT_CLASS
@interface NSProxy <NSObject> {
    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 NS_UNAVAILABLE;
- (BOOL)retainWeakReference NS_UNAVAILABLE;
@end
  1. NSProxyNSObject一样是NS_ROOT_CLASS,也就是根类
  2. NSProxy是实现@protocol NSObject,而不是继承@interface NSObject
  3. NSProxy没有消息转发的第一步和第二步,直接到第三步,NSProxy也没有实现对应方法

实际上可当做NSProxy没有实现什么实例方法,虽然- (Class)class方法还是实现了。

这就使得

  1. NSProxy非常单纯,干净,不像NSObject有很多分类,有很多方法不能转发
  2. NSProxy方法少,凡是NSProxy没有实现的方法都是可以转发的,也就是几乎所有的方法都可以转发
  3. NSProxy设计的代理类能够更加纯正

NSProxy的用途

  1. AOP
  2. 代理模式、Decorator模式,这里有一个简单的demo,可以参考
  3. 多继承,通过引用多个target模拟多继承。