NSProxy

作者: Yongle_jianshu | 来源:发表于2018-12-13 16:09 被阅读0次

概念

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等

相关文章

  • 重拾iOS-NSProxy

    关键词:NSProxy,NSObject,Runtime 面试题:1)知道NSProxy吗?2)NSProxy和N...

  • NSProxy

    NSProxy.h文件内容 NSProxy 是一个抽象类NSProxy遵守了 NSObject 协议,内部有它的 ...

  • NSProxy、NSInvocation、NSMethodSig

    什么是NSProxy: NSProxy是一个抽象的基类,是根类,与NSObject类似 NSProxy和NSObj...

  • [iOS] 七七八八的小姿势(2)

    目录: NSProxy 字典集合对成员的引用方式 class判断 block变量捕获 1. NSProxy NSP...

  • NSProxy 和 NSObject 关系

    一、NSProxy 简介NSProxy 是一个抽象类,它实现了protocol NSObject 所要求的基本方法...

  • 老生常谈之NSProxy和NSTimer

    网上NSProxy和NSTimer都写烂了,所以这里只做下总结: 1.NSProxy应用场景: 解决NSTimer...

  • NSProxy

    NSProxy——少见却神奇的类 - IOS - 伯乐在线

  • NSProxy

    吾尝以为NSObject是Apple的所有Objective-C引用类型的老祖宗,直到后来知道了NSProxy的存...

  • NSProxy

    作用一: 代理想要拦截自定义CPTabBarController(UITabBarController子类)中ta...

  • NSProxy

    它来实现一下"伪多继承". 直接上个代码来展示下 使用方法 控制台输出结果 发现没有,猫发出消息已经被子类的内部拦...

网友评论

      本文标题:NSProxy

      本文链接:https://www.haomeiwen.com/subject/xuzvhqtx.html