iOS Class uses NSProxy and NSObject to design the difference of proxy class

It is often found that when creating proxy classes that need to use message forwarding, different programmers have different methods of use. Some use inheritance from NSObject, and some use inheritance from NSProxy. Both are base classes in the Foundation framework. And they all implement <NSObject>this interface. From the naming and documentation, NSProxy is born to do this. But even so, they all define the same message forwarding interface, so when we use both to complete this work What's the difference?

First post the most basic implementation code for creating a proxy class through the two.

Inherited from 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

Inherited from 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

The code is basically the same, except for the detailed differences in the specification of the initialization. This difference is because the base class of NSProxy does not define the default init method.

1. After testing, it is found that the following two <NSObject>interfaces defined in are inconsistent between the two:

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

The results will output different conclusions:

1
2
1 0
1 0

That is to say, the proxy class inherited from NSObject will not automatically forward the two methods respondsToSelector: and isKindOfClass:, while the proxy class inherited from NSProxy is possible. <NSObject>The other interfaces defined in the test behave the same. of.

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>接口中定义的部分方法), 所以其它方法都能够按照设计的预期被转发到被代理的对象中.

Guess you like

Origin blog.csdn.net/wangletiancsdn/article/details/98042488
Recommended