Objective-c NSProxy

 

Objective-c 语言中的类在声明时,必须指明它的父类。 NSObjectNSProxy是 Objective-c提供的顶级父类,每一个OC类最终都会继承其中一个。绝大部分的OC类都会继承于NSObject,而少部分继承于NSProxy

NSProxy

NSProxy是一个抽象父类,定义了一套API,作为其他对象或者不存在的对象的替身或者代理。

通常,当NSProxy收到消息,会转发给真实的对象或者加载真实对象(真实对象懒加载)。NSProxy的子类必须实现分发消息和创建初始化真实对象的逻辑。

NSProxy子类的实现

NSProxy实现了根父类必须的基本方法,包括NSObject协议声明的方法。但是,作为抽象类它没有提供任何初始化方法,并且当收到无法处理的消息时会抛出异常。

NSProxy派生的子类必须提供初始化方法并重写forwardInvocation:methodSignatureForSelector:方法。

最佳实践 利用NSProxy实现弱引用代理

利用NSProxy作为真实对象的代理,发送到NSProxy的消息都会转发到真实对象。真实对象以弱引用的方式被NSProxy持有。

这种设计常常在需要避免引用循环的时候使用。


// 在这个方法中,target会被NSTimer强引用
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo;

提供初始化方法


// 为NSProxy提供初始化的方法,并声明一个弱引用属性保存真实对象

@interface ZLWeakProxy : NSProxy

@property(nonatomic, weak, readonly) id object;

- (instancetype) initWithObject:(id) object;

+ (instancetype) proxyWithObject:(id) object;

@end


@implementation ZLWeakProxy

- (instancetype) initWithObject:(id)object {
    _object = object;
    return self;
}

+ (instancetype) proxyWithObject:(id)object {
    return [[self alloc] initWithObject:object];
}

@end


重写NSProxy的基本方法


// 调用基本方法重写为调用真实对象的相应方法

@implementation ZLWeakProxy

- (BOOL)isEqual:(id)object{
    return [_object isEqual:object];
}

- (NSUInteger) hash {
    return [_object hash];
}

- (Class) class {
    return [_object class];
}

- (Class)superclass {
    return [_object superclass];
}

- (BOOL)isKindOfClass:(Class)aClass{
    return [_object isKindOfClass:aClass];
}
- (BOOL)isMemberOfClass:(Class)aClass{
    return [_object isMemberOfClass:aClass];
}
- (BOOL)conformsToProtocol:(Protocol *)aProtocol{
    return [_object conformsToProtocol:aProtocol];
}

- (BOOL) respondsToSelector:(SEL)aSelector {
    return [_object respondsToSelector:aSelector];
}

- (BOOL) isProxy {
    return YES;
}

- (NSString *)description {
    return [_object description];
}

- (NSString *)debugDescription {
    return [_object debugDescription];
}

@end

重写消息转发的方法


// 利用消息转发机制 将无法识别的消息转发给真实的对象

@implementation ZLWeakProxy

- (id)forwardingTargetForSelector:(SEL)selector {
    return _object;
}

- (void)forwardInvocation:(NSInvocation *)invocation {
    void *null = NULL;
    [invocation setReturnValue:&null];
}

- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel{
    return [_object methodSignatureForSelector:sel];
}

@end

ZLWeakProxy