經(jīng)常發(fā)現(xiàn)在一些需要使用消息轉發(fā)而創(chuàng)建代理類時, 不同的程序員都有著不同的使用方法, 有些采用繼承于NSObject, 而有一些采用繼承自NSProxy. 二者都是Foundation框架中的基類, 并且都實現(xiàn)了<NSObject>這個接口, 從命名和文檔中看NSProxy天生就是用來干這個事情的. 但即便如此, 它們卻都定義了相同的消息轉發(fā)的接口, 那我們在使用二者來完成這個工作時有什么差異呢.
先貼一下通過二者來創(chuàng)建代理類的最基本實現(xiàn)代碼.
繼承自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
代碼基本是一致的, 除了初始化時規(guī)范的寫法有細節(jié)差異, 這個差異是因為NSProxy這個基類沒有定義默認的init方法.
1.經(jīng)測試發(fā)現(xiàn)以下兩個在<NSObject>
中定義的接口, 在二者之間表現(xiàn)是不一致的:
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的代理類是不會自動轉發(fā)respondsToSelector:
和isKindOfClass:
這兩個方法的, 而繼承自NSProxy的代理類卻是可以的. 測試<NSObject>
中定義的其它接口二者表現(xiàn)都是一致的.
2.NSObject的所有Category中定義的方法無法在XCObject中完成轉發(fā)莫杈。
舉一個很常見的例子, valueForKey:
是定義在NSKeyValueCoding
這個NSObject的Category
中的方法, 嘗試二者執(zhí)行的表現(xiàn).
NSLog(@"proxy valueForKey %@", [p valueForKey:@"length"]);
NSLog(@"object valueForKey %@", [o valueForKey:@"length"]);
這段代碼第一句能正確運行, 但第二行卻會拋出異常, 分析最終原因其實很簡單, 因為valueForKey:
是NSObject的Category
中定義的方法, 讓NSObject具備了這樣的接口, 而消息轉發(fā)是只有當接收者無法處理時才會通過forwardInvocation:
來尋求能夠處理的對象术羔。