概念
NSProxy
是一个实现NSObject
协议的根类
@protocol NSObject
- (BOOL)isEqual:(id)object;
@property (readonly) NSUInteger hash;
@property (readonly) Class superclass;
- (Class)class OBJC_SWIFT_UNAVAILABLE("use 'type(of: anObject)' instead");
- (instancetype)self;
- (id)performSelector:(SEL)aSelector;
- (id)performSelector:(SEL)aSelector withObject:(id)object;
- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;
- (BOOL)isProxy;
- (BOOL)isKindOfClass:(Class)aClass;
- (BOOL)isMemberOfClass:(Class)aClass;
- (BOOL)conformsToProtocol:(Protocol *)aProtocol;
- (BOOL)respondsToSelector:(SEL)aSelector;
- (instancetype)retain OBJC_ARC_UNAVAILABLE;
- (oneway void)release OBJC_ARC_UNAVAILABLE;
- (instancetype)autorelease OBJC_ARC_UNAVAILABLE;
- (NSUInteger)retainCount OBJC_ARC_UNAVAILABLE;
- (struct _NSZone *)zone OBJC_ARC_UNAVAILABLE;
@property (readonly, copy) NSString *description;
@optional
@property (readonly, copy) NSString *debugDescription;
@end
NS_ROOT_CLASS
@interface NSProxy <NSObject>{
Class isa;
}
+ (id)alloc;
+ (id)allocWithZone:(nullable NSZone *)zone NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
+ (Class)class;
- (void)forwardInvocation:(NSInvocation *)invocation;
- (nullable NSMethodSignature *)methodSignatureForSelector:(SEL)sel NS_SWIFT_UNAVAILABLE("NSInvocation and related APIs not available");
- (void)dealloc;
- (void)finalize;
@property (readonly, copy) NSString *description;
@property (readonly, copy) NSString *debugDescription;
+ (BOOL)respondsToSelector:(SEL)aSelector;
- (BOOL)allowsWeakReference NS_UNAVAILABLE;
- (BOOL)retainWeakReference NS_UNAVAILABLE;
@end
使用
恰如其名,作为代理使用,通过消息转发实现
e.g.
@interface ProxyA : 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
//case
NSString *string = @"test";
ProxyA *proxyA = [[ProxyA alloc] initWithObject:string];
NSLog(@"%d", [proxyA respondsToSelector:@selector(length)]);
NSLog(@"%d", [proxyA isKindOfClass:[NSString class]]);
NSLog(@"%@",[proxyA valueForKey:@"length"]);
结果输出 1
1
4
分析下结果,没找到NSProxy
源码,因此反编译了下
char -[NSProxy isKindOfClass:](void * self, void * _cmd, void * arg2) {
r6 = _NSMessageBuilder();
[r6 isKindOfClass:arg2];
object_dispose(r6);
[self forwardInvocation:0x0];
r0 = [0x0 getReturnValue:sp - 0x8];
asm{ ldrsb.w r0, [sp, #0x14 + var_14] };
return r0;
}
char -[NSProxy respondsToSelector:](void * self, void * _cmd, void * arg2) {
r6 = _NSMessageBuilder();
[r6 respondsToSelector:arg2];
object_dispose(r6);
[self forwardInvocation:0x0];
r0 = [0x0 getReturnValue:sp - 0x8];
asm{ ldrsb.w r0, [sp, #0x14 + var_14] };
return r0;
}
int __NSMessageBuilder(int arg0, int arg1) {
r0 = <redacted>_21a18f90("__NSMessageBuilder");
r0 = class_createInstance(r0, 0x0);
r0->_target = arg0;
r0->_addr = arg1;
return r0;
}
void -[__NSMessageBuilder forwardInvocation:](void * self, void * _cmd, void * arg2) {
r4 = self;
r5 = arg2;
[r5 setTarget:r4->_target, r3, var_14];
if (r4->_addr != 0x0) {
*r4->_addr = [[r5 retain] autorelease];
}
return;
}
从得到的伪码能够看出
isKindOfClass:
和respondsToSelector:
会直接调用
自身forwardInvocation:
而
valueForKey:
找不到method时最终也会通过消息转发进入自身forwardInvocation:
来看下NSObject
- (BOOL)isKindOfClass:(Class)cls {
for (Class tcls = [self class]; tcls; tcls = tcls->superclass) {
if (tcls == cls) return YES;
}
return NO;
}
- (BOOL)respondsToSelector:(SEL)sel {
if (!sel) return NO;
return class_respondsToSelector_inst([self class], sel, self);
}
如果将前面的ProxyA改为继承NSObject时结果将输出
0
0
抛异常
结论: NSProxy更适合实现做为消息转发的代理类,实际操作中可用于模拟多重继承、AOP等
网友评论