iOS NSProxy和NSObject设计代理类差异

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

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

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

继承自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.经测试发现以下两个在<NSObject>中定义的接口, 在二者之间表现是不一致的:
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的代理类却是可以的. 测试<NSObject>中定义的其它接口二者表现都是一致的.

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:来寻求能够处理的对象。

3.结论: 如此看来NSProxy确实更适合实现做为消息转发的代理类, 因为作为一个抽象类, NSProxy自身能够处理的方法极小(仅<NSObject>接口中定义的部分方法), 所以其它方法都能够按照设计的预期被转发到被代理的对象中。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 1.设计模式是什么? 你知道哪些设计模式,并简要叙述? 设计模式是一种编码经验,就是用比较成熟的逻辑去处理某一种类...
    司马DE晴空阅读 5,193评论 0 7
  • 简介 Runtime 又叫运行时,是一套底层的 C 语言 API,其为 iOS 内部的核心之一,我们平时编写的 O...
    专业男神经阅读 4,408评论 0 2
  •   最近看了『神奇的 BlocksKit』系列,里面说到动态代理是BlocksKit的精华部分,对于使用block...
    foreverSun_122阅读 4,922评论 1 7
  • 在清明这个节日上,我们都不会说清明节快乐,因为都知道这不是我们的节日,是哪些逝去的人的节日。 死亡是一件恐怖的事,...
    op牵绊阅读 1,526评论 0 1
  • 水陆草木之花,可爱者甚蕃。晋陶渊明独爱菊。自李唐来,世人盛爱牡丹。 予独爱莲之出淤泥而不染,濯清涟而不妖,中通外直...
    素素就是团子他娘阅读 3,535评论 2 5

友情链接更多精彩内容