转自:使用NSProxy和NSObject设计代理类的差异
经常发现在一些需要使用消息转发而创建代理类时, 不同的程序员都有着不同的使用方法, 有些采用继承于NSObject, 而有一些采用继承自NSProxy. 二者都是Foundation框架中的基类, 并且都实现了
先贴一下通过二者来创建代理类的最基本实现代码.
继承自NSProxy
#import "XCProxy.h"
@interface XCProxy ()
@property (strong, nonatomic) id target;
@end
@implementation XCProxy
- (id)initWithObject:(id)object {
self.target = object;
return self;
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel {
return [self.target methodSignatureForSelector:sel];
}
- (void)forwardInvocation:(NSInvocation *)invocation {
[invocation invokeWithTarget:self.target];
}
@end
继承自NSObject
@interface XCObject ()
@property (strong, nonatomic) id target;
@end
@implementation XCObject
- (id)initWithObject:(id)object {
self = [super init];
if (self) {
self.target = object;
}
return self;
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
return [self.target methodSignatureForSelector:aSelector];
}
- (void)forwardInvocation:(NSInvocation *)anInvocation {
[anInvocation invokeWithTarget:self.target];
}
@end
代码基本是一致的, 除了初始化时规范的写法有细节差异, 这个差异是因为NSProxy这个基类没有定义默认的init方法.
1.经测试发现以下两个在
中定义的接口, 在二者之间表现是不一致的:
NSString *test = @"testString";
XCProxy *p = [[XCProxy alloc] initWithObject:test];
XCObject *o = [[XCObject alloc] initWithObject:test];
NSLog(@"proxy length %d", [p respondsToSelector:@selector(length)]);
NSLog(@"object length %d", [o respondsToSelector:@selector(length)]);
NSLog(@"proxy kindOfClass %d", [p isKindOfClass:[NSString class]]);
NSLog(@"object kindOfClass %d", [o isKindOfClass:[NSString class]]);
结果会输出完成不同的结论:
proxy length 1
object length 0
proxy kindOfClass 1
object kindOfClass 0
也就是说通过继承自NSObject的代理类是不会自动转发respondsToSelector:
和isKindOfClass:
这两个方法的, 而继承自NSProxy的代理类却是可以的. 测试
中定义的其它接口二者表现都是一致的.
2.NSObject的所有Category中定义的方法无法在XCObject中完成转发。
举一个很常见的例子, valueForKey:
是定义在NSKeyValueCoding
这个NSObject的Category
中的方法, 尝试二者执行的表现.
NSLog(@"proxy valueForKey %@", [p valueForKey:@"length"]);
NSLog(@"object valueForKey %@", [o valueForKey:@"length"]);
这段代码第一句能正确运行, 但第二行却会抛出异常, 分析最终原因其实很简单, 因为valueForKey:
是NSObject的Category
中定义的方法, 让NSObject具备了这样的接口, 而消息转发是只有当接收者无法处理时才会通过forwardInvocation:
来寻求能够处理的对象。