在ViewController 里面有一个NSTimer
@interface ViewController ()
@property (nonatomic,strong)NSTimer *timer;
@end
- (void)viewDidLoad {
[super viewDidLoad];
self.timer = [NSTimer scheduledTimerWithTimeInterval:3 target:[GLDNSProxy proxyWithTarget:self] selector:@selector(timerEvent) userInfo:nil repeats:YES];
}
- (void)timerEvent{
NSLog(@"%s",__func__);
}
-(void)dealloc{
NSLog(@"%s",__func__);
[self.timer invalidate];
}
NStimer 中的target 强引用 VC,VC强引用timer,互相持有,形成了一个循环圏,VC的dealloc永不会被执行,time也不被销毁,造成内存泄漏
解决方法
使用中间类,让timer的target 强引用中间类otherObjct,而otherObjct 的Target弱引用VC
@interface GLDNSProxy : NSObject
@property (nonatomic,weak)id target; //弱引用
+(instancetype)proxyWithTarget:(id)target;
@end
#import "GLDNSProxy.h"
@implementation GLDNSProxy
+(instancetype)proxyWithTarget:(id)target{
GLDNSProxy *proxy = [[GLDNSProxy alloc] init];
proxy.target = target;
return proxy;
}
//为了使用调用GLDNSProxy所有方法都转变给target处理
//使用消息转发
-(id)forwardingTargetForSelector:(SEL)aSelector
{
return self.target;//把消息转发给VC处理
}
VIewController中使用
- 传进去的target为GLDNSProxy对象,而GLDNSProxy对象弱引用VC
所以每隔3秒就会调用一次GLDNSProxy的timerEvent的方法,而GLDNSProxy使用消息转发机制将方法转发给了VC,最终还是调用的VC中的timerEvent
self.timer = [NSTimer scheduledTimerWithTimeInterval:3 target:[GLDNSProxy proxyWithTarget:self] selector:@selector(timerEvent) userInfo:nil repeats:YES];
最终解决方案
使用iOS的NSProxy类,NSProxy就是专门用来做消息转发的。
@interface GLDNSProxy : NSProxy
@property (nonatomic,weak)id target;
+(instancetype)proxyWithTarget:(id)target;
@end
@implementation GLDNSProxy
+(instancetype)proxyWithTarget:(id)target{
GLDNSProxy *proxy = [GLDNSProxy alloc];
proxy.target = target;
return proxy;
}
-(NSMethodSignature *)methodSignatureForSelector:(SEL)sel
{
return [self.target methodSignatureForSelector:sel];
}
-(void)forwardInvocation:(NSInvocation *)invocation
{
[invocation invokeWithTarget:self.target];
}
两种方式相比,继承NSProxy比继承NSObject效率高
继承NSProxy,只看自己类里面有没有,如果没有直接进入消息转发,不会去父类里查找方法.