iOS中的NSProxy
2018-07-19 本文已影响25人
伶俐ll
NSProxy是和NSObject同级的一个类,可以说它是一个虚拟类,它只是实现了<NSObject>的协议,用来专门做消息转发。
详见如下代码:
//LZProxy.h
#import <Foundation/Foundation.h>
@interface LZProxy : NSProxy
+ (instancetype)proxyWithTarget:(id)target;
@property (weak, nonatomic) id target;
@end
#import "LZProxy.h"
@implementation MJProxy
+ (instancetype)proxyWithTarget:(id)target
{
// NSProxy对象不需要调用init,因为它本来就没有init方法
MJProxy *proxy = [MJProxy alloc];
proxy.target = target;
return proxy;
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel
{
return [self.target methodSignatureForSelector:sel];
}
- (void)forwardInvocation:(NSInvocation *)invocation
{
//可以在这里拦截方法的参数返回值等相关信息,具体Runtime那篇文章有详细介绍
[invocation invokeWithTarget:self.target];
}
@end
#import "ViewController.h"
#import "LZProxy.h"
@interface ViewController ()
@property (strong, nonatomic) NSTimer *timer;
@property (strong, nonatomic) CADisplayLink *link;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 保证调用频率和屏幕的刷帧频率一致,60FPS
self.link = [CADisplayLink displayLinkWithTarget:[LZProxy proxyWithTarget:self] selector:@selector(linkTest)];
[self.link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:[LZProxy proxyWithTarget:self] selector:@selector(timerTest) userInfo:nil repeats:YES];
}
- (void)timerTest
{
NSLog(@"%s", __func__);
}
- (void)linkTest
{
NSLog(@"%s", __func__);
}
- (void)dealloc
{
NSLog(@"%s", __func__);
[self.timer invalidate];
}
@end
- 当给LZProxy类的对象发送消息时,Runtime不会执行消息发送阶段和动态方法解析阶段,直接进行消息转发,系统会直接调用
methodSignatureForSelector:
方法返回方法签名。 - 在这里通过实现消息转发,解决了timer、link和控制器的循环引用问题。
另:分析下面程序的打印结果
ViewController *vc = [[ViewController alloc] init];
LZProxy *proxy = [LZProxy proxyWithTarget:vc];
NSLog(@"%d", [proxy isKindOfClass:[ViewController class]]); //1
- 给NSProxy类的对象发送消息会直接进入消息转发阶段,调用
methodSignatureForSelector:
方法,返回方法签名,然后forwardInvocation:
方法,在这个方法内部进行消息转发,此时调用isKindOfClass:
方法的对象就是vc,因此打印结果是1