NSProxy

概念

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 {
    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 = _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等

你可能感兴趣的:(NSProxy)