iOS Class 使用NSProxy和NSObject设计代理类的差异

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

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

继承自NSProxy

1234567891011121314151617181920
@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

1234567891011121314151617181920212223
@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>中定义的接口, 在二者之间表现是不一致的:

123456789
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]]);

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

12
1 01 0

也就是说通过继承自NSObject的代理类是不会自动转发respondsToSelector:和isKindOfClass:这两个方法的, 而继承自NSProxy的代理类却是可以的. 测试<NSObject>中定义的其它接口二者表现都是一致的.

2.NSObject的所有Category中定义的方法无法在THProxyB中完成转发

举一个很常见的例子, valueForKey:是定义在NSKeyValueCoding这个NSObject的Category中的方法, 尝试二者执行的表现.

12
NSLog(@"%@",[proxyA valueForKey:@"length"]);NSLog(@"%@",[proxyB valueForKey:@"length"]);

这段代码第一句能正确运行, 但第二行却会抛出异常, 分析最终原因其实很简单, 因为valueForKey:是NSObject的Category中定义的方法, 让NSObject具备了这样的接口, 而消息转发是只有当接收者无法处理时才会通过forwardInvocation:来寻求能够处理的对象.

3.结论: 如此看来NSProxy确实更适合实现做为消息转发的代理类, 因为作为一个抽象类, NSProxy自身能够处理的方法极小(仅<NSObject>接口中定义的部分方法), 所以其它方法都能够按照设计的预期被转发到被代理的对象中.

 

时间: 2024-11-11 11:48:30

iOS Class 使用NSProxy和NSObject设计代理类的差异的相关文章

使用NSProxy和NSObject设计代理类的差异

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

麦子学院干货 | iOS开发者需要的九大设计工具

麦子学院[www.maiziedu.com]干货 | iOS开发者需要的九大设计工具 1.AppCooker AppCooker是一款方便的iPad应用.它能够提供可点击的原型模板,集合了所有需要编码或渲染的重要部件,并且还可以帮助开发者无需任何代码编写就能够构思.设计和测试iOS应用.目前AppCooker在App Store上的售价为19.99美元. 主要功能: 全功能模型编辑器拥有所有iOS UI部件 位图图画.矢量形状和文本工具 带有链接的整体屏幕视图 收存箱和Box支持云服务 2.Sk

《C++沉思录》——类设计核查表、代理类、句柄类

<C++沉思录>集中反映C++的关键思想和编程技术,讲述如何编程,讲述为什么要这么编程,讲述程序设计的原则和方法,讲述如何思考C++编程. 一.类设计核查表 1.你的类需要一个构造函数吗? 2.你的数据成员都是私有的合理吗? 3.你的类需要一个无参的构造函数吗? 是否需要生成类对象的数组! 4.你的每一个构造函数都初始化所有的数据成员了吗? 虽然这种说法未必总是正确,但是要积极思考! 5.你的类需要析构函数吗? 6.你的类需要一个虚析构函数吗? 7.你的类需要一个拷贝构造函数吗? 8.你的类需

C++代理类设计(一)

作用:使设计的容器有能力包含类型不同而彼此相关的对象. 容器通常只能包含一种类型的对象,所以很难再容器中存储对象本身.存储指向对象的指针,虽然允许通过继承来处理类型不同的问题(多态性),但是也增加了内存分配的额外负担.所以我们通过定义名为代理的对象来解决该问题.代理运行起来和它所代表的对象基本相同,但是允许将整个派生层次压缩在一个对象类型中. 假设有一个表示不同种类的交通工具的类派生层次: class Vehicle { public: virtual double weight() const

ios 中代理类汇总

ios 代理类总结一下.今后多看看 UITextViewDelegate UIToolbarDelegate UITextInputDelegate UITextFieldDelegate UIWebViewDelegate NSLayoutManagerDelegate //UIActionSheet //UIActionSheetDelegate 要放弃 //UIAlertView  要放弃 //UIAlertViewDelegate //优先使用preferred //UIAlertCon

设计代理模式理解

通常情况下,一个类引用了另一个类时,都会有一个相关联待属性,比如person类中有一个student类型的属性,这样使用导致代码的耦合性 太高,一旦我不想使用student作为该属性的类型时,即这个类型是个代理类,修改起代码十分的麻烦, 所有我们就直接将这个属性定义成id类型的(NSObject *),可以是任意类型,但是此时当类型实质是没有明确的的,那么就会导致我们无法 使用该属性, 所有我们又让这个id类型去遵守某个协议,那么这样我们就知道这个id类型的实质是要干啥,也就是我们能够清楚知道这

iOS开发之oc(回顾笔记)--类与对象(1)

理论是枯燥的,所以有点长.哈哈哈~ 要学习一门语言,我们首先得了解它,那么 [什么是OC] objectiv-c  简称 OC,是一门基于C语言为基础编写而成的面向对象的语言.完全兼容C语言:可以在OC代码中混入C语言代码,甚至是C++代码: 可以使用OC开发Mac OS X平台和iOS平台的应用程序. (一)首先,先了解一下面向过程和面向对象: [面向过程] 1.面向过程的语言所有语句都是祈使句  2.面向过程的语言是数学逻辑的映射 3.面向过程语言的程序 = 数据 + 算法 C语言就是一门面

c++ 沉思录---代理类

一.问题 如何设计一容器能包含彼此不同而又相互关联的类的对象(处于完整的继承层次的类)?因为一般的数组容器都只能包含一种类型的对象. 假设有一个表示不同类型的交通工具的类的派生层次: class Vehicle { public: virtual double weight () const = 0; virtual void start() = 0; //..... }; class RoadVehicle : public Vehicle { public: /* data */ }; cl

【C++沉思录】代理类

1.考虑下面的场景:设计一个容器,包含一组类型不同但相互关联的对象(比如:Animal,Dog,Cat),对象具备多态行为.2.容器一般只能包含一种类型的对象,使用vector<Animal> 会造成对象切割,不具备多态行为.3.经典的解决办法是:vector<Animal*>, 但是这会增加内存管理的负担.考虑下面的情况: Dog d; vec[i] = &d; // 局部对象d销毁, vec[i] 指向垃圾 vec[i] = vec[j]; // 指向同一个对象, 在v