NSProxy 设计消息转发
- 2019 年 10 月 8 日
- 筆記
首先,了解下NSTimer的循环引用
@interface ViewController () @property (nonatomic, strong) NSTimer *timer; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(testForTimer) userInfo:nil repeats:YES]; } - (void)testForTimer { NSLog(@"%s",__func__); } @end
循环引用:

mage
- 可能有的人说用
__weak
来修饰self
从而达到targe
t指向ViewController
是弱引用的效果。 - 不行! 因为weak 也是把地址赋值给
target
,target
还是强引用viewController
地址。我们用的weak是处理block的循环引用,block中会把__weak
修饰的对象 描述为弱引用

关于SRProxy
@interface SRProxy : NSProxy @property (nonatomic, weak) id target; + (instancetype)proxyWithTarget:(id)target; @end
@implementation SRProxy + (instancetype)proxyWithTarget:(id)target { SRProxy *proxy = [SRProxy alloc]; proxy.target = target; return proxy; } - (id)forwardingTargetForSelector:(SEL)aSelector { if (self.target) { return self.target; } return self; } -(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector { return [self.target methodSignatureForSelector:aSelector]; } - (void)forwardInvocation:(NSInvocation *)invocation { [invocation invokeWithTarget:self.target]; } @end
关于解决方式
self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:[SRProxy proxyWithTarget:self] selector:@selector(testForTimer) userInfo:nil repeats:YES];
解释NSProxy
结构
@interface NSProxy <NSObject> { Class isa; }
NSProxy为基类,和NSObject同级, 专门处理这种代理实现事件。
SRProxy继承于NSProxy 如果继承NSObject 也可以实现功能。
NSProxy 和NSObject比较
继承于NSProxy的类 找实现方法的时候 只会找当前类是否实现 而不找super,如果没找到直接进入消息动态解析,以及消息转发机制。比继承NSObject的类少了找super,从而效率更高。
实验1
如果把SRProxy中的消息转发机制去掉 看一下错误信息
继承NSProxy

继承NSObject

NSProxy没有init方法 只要alloc 既可
实验2
当我们继承于NSProxy 在上述ViewDidLoad
中打印此代码 结果为
NSLog(@"isKindOfClass == %d",[[SRProxy proxyWithTarget:self] isKindOfClass:[self class]]);

解释
调用isKindOfClass
进行消息转发 走的是下面的方法
-(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector { return [self.target methodSignatureForSelector:aSelector]; }
- (void)forwardInvocation:(NSInvocation *)invocation { [invocation invokeWithTarget:self.target]; }
实际调用的是self.target
去执行objc_msgSend(self.target,SEL)
所以为1
isKindOfClass 为1