NSProxy

概念

NSProxy是一個實現(xiàn)NSObject協(xié)議的根類

@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

使用

恰如其名,作為代理使用,通過消息轉(zhuǎn)發(fā)實現(xiàn)

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

結(jié)果輸出 1 1 4

分析下結(jié)果,沒找到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:會直接調(diào)用
自身forwardInvocation:

valueForKey:找不到method時最終也會通過消息轉(zhuǎn)發(fā)進入自身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時結(jié)果將輸出 0 0 拋異常

結(jié)論: NSProxy更適合實現(xiàn)做為消息轉(zhuǎn)發(fā)的代理類,實際操作中可用于模擬多重繼承、AOP等

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容