メッセージ転送を使用する必要のあるプロキシクラスを作成する場合、プログラマーによって使用方法が異なることがよくあります。NSObjectからの継承を使用するものと、NSProxyからの継承を使用するものがあります。どちらもFoundationフレームワークの基本クラスです。そして、それらはすべて<NSObject>
このインターフェースを実装しています。命名とドキュメントから、NSProxyはこれを行うために生まれました。しかし、それでも、それらはすべて同じメッセージ転送インターフェースを定義しているので、両方を使用してこの作業を完了すると違いは何ですか?
最初に、2つを介してプロキシクラスを作成するための最も基本的な実装コードを投稿します。
NSProxyから継承
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
@interface THProxyA:NSProxy @property(nonatomic、strong)id target; @end @implementation THProxyA- (id)initWithObject:(id)object { self.target = object; 自己を返す; } -(NSMethodSignature *)methodSignatureForSelector:(SEL)selector { return [self.target methodSignatureForSelector:selector]; } -(void)forwardInvocation:(NSInvocation *)invocation { [invocation invokeWithTarget:self.target]; } @end |
NSObjectから継承
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
@interface THProxyB:NSObject @property(nonatomic、strong)id target; @end @implementation THProxyB- (id)initWithObject:(id)object { self = [super init]; if(self){ self.target = object; } 自己を返す; } -(NSMethodSignature *)methodSignatureForSelector:(SEL)selector { return [self.target methodSignatureForSelector:selector]; } -(void)forwardInvocation:(NSInvocation *)invocation { [invocation invokeWithTarget:self.target]; } @end |
初期化の仕様の詳細な違いを除いて、コードは基本的に同じです。この違いは、NSProxyの基本クラスがデフォルトのinitメソッドを定義していないためです。
1.テストの結果、で<NSObject>
定義されている次の2つのインターフェイスが2つの間で矛盾していることがわかりました。
1 2 3 4 5 6 7 8 9 |
NSString * string = @ "test"; THProxyA * proxyA = [[THProxyA alloc] initWithObject:string]; THProxyB * proxyB = [[THProxyB alloc] initWithObject:string]; NSLog(@ "%d"、[proxyA responsesToSelector:@selector(length)]); NSLog(@ "%d"、[proxyB responsesToSelector:@selector(length)]); NSLog(@ "%d"、[proxyA isKindOfClass:[NSString class]]); NSLog(@ "%d"、[proxyB isKindOfClass:[NSString class]]); |
結果は異なる結論を出力します:
1 2 |
1 0 1 0 |
つまり、NSObjectから継承されたプロキシクラスは、2つのメソッドrespondsToSelector:とisKindOfClass:を自動的に転送しませんが、NSProxyから継承されたプロキシクラスは可能です。テストで<NSObject>
定義された他のインターフェイスのパフォーマンスは同じです。の。
2.NSObject的所有Category中定义的方法无法在THProxyB中完成转发
举一个很常见的例子, valueForKey:是定义在NSKeyValueCoding这个NSObject的Category中的方法, 尝试二者执行的表现.
1 2 |
NSLog(@"%@",[proxyA valueForKey:@"length"]); NSLog(@"%@",[proxyB valueForKey:@"length"]); |
这段代码第一句能正确运行, 但第二行却会抛出异常, 分析最终原因其实很简单, 因为valueForKey:是NSObject的Category中定义的方法, 让NSObject具备了这样的接口, 而消息转发是只有当接收者无法处理时才会通过forwardInvocation:来寻求能够处理的对象.
3.结论: 如此看来NSProxy确实更适合实现做为消息转发的代理类, 因为作为一个抽象类, NSProxy自身能够处理的方法极小(仅<NSObject>
接口中定义的部分方法), 所以其它方法都能够按照设计的预期被转发到被代理的对象中.