你的位置:首页 > 操作系统

[操作系统]iOS Class 使用NSProxy和NSObject设计代理类的差异


  经常发现在一些需要使用消息转发而创建代理类时, 不同的程序员都有着不同的使用方法, 有些采用继承于NSObject, 而有一些采用继承自NSProxy. 二者都是Foundation框架中的基类, 并且都实现了<NSObject>这个接口, 从命名和文档中看NSProxy天生就是用来干这个事情的. 但即便如此, 它们却都定义了相同的消息转发的接口, 那我们在使用二者来完成这个工作时有什么差异呢.

先贴一下通过二者来创建代理类的最基本实现代码.

继承自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;
return self;
}

- (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;
}
return self;
}

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

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

@end

代码基本是一致的, 除了初始化时规范的写法有细节差异, 这个差异是因为NSProxy这个基类没有定义默认的init方法.

1.经测试发现以下两个在<NSObject>中定义的接口, 在二者之间表现是不一致的:

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 respondsToSelector:@selector(length)]);
NSLog(@"%d", [proxyB respondsToSelector:@selector(length)]);

NSLog(@"%d", [proxyA isKindOfClass:[NSString class]]);
NSLog(@"%d", [proxyB isKindOfClass:[NSString class]]);

结果会输出完成不同的结论:

1
2
1 0
1 0

也就是说通过继承自NSObject的代理类是不会自动转发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>接口中定义的部分方法), 所以其它方法都能够按照设计的预期被转发到被代理的对象中.

 





去巴厘岛旅游攻略巴厘岛六日游行程安排参考去巴厘岛旅游跟团行程巴厘岛旅游护照签证巴厘岛旅游路线报价费用2015深圳欢乐谷圣诞节儿童票多少钱?深圳欢乐谷圣诞节适合多大儿童玩? 2015圣诞节深圳欢乐谷门票多少钱?深圳欢乐谷圣诞节门票价格? 2015深圳欢乐谷圣诞节什么时间开始?深圳欢乐谷圣诞节活动什么时间结束? 2015深圳欢乐谷圣诞节有什么活动?深圳欢乐谷圣诞节活动介绍? 澳门环岛夜游门票价格?珠海澳门环岛夜游门票包含什么? 珠海澳门环岛船游门票多少钱?澳门环岛船游网上可以预订吗? 澳门环岛游日游多少钱?珠海澳门环岛游日游和夜游有什么区别? 韶关鸿润生态园野战票多少钱?鸿润生态园野战怎么收费? 台湾各地美食指南,台湾各地有哪些美食,台湾美食分布 跟随《少年派》展开一段奇妙的印度旅程,印度少年派,印度之旅 春节出境游 手续办理知多少 峨眉山冬季旅游注意事项 蒙古族的那达慕大会 厦门鼓浪屿不可错过特色美食 黄帝陵门票_西安轩辕黄帝陵门票价格 厦门鼓浪屿最佳旅游时间 HL-50103GD Datasheet HL-50103GD Datasheet HL-50103GT Datasheet HL-50103GT Datasheet HL-50103HD Datasheet HL-50103HD Datasheet 3月适合去哪儿旅游 3月适合去哪儿旅游 3月适合去哪儿旅游 2月适合到哪里旅游 2月适合到哪里旅游 2月适合到哪里旅游 3月到哪旅游 3月到哪旅游 3月到哪旅游