解决NSTimer 循环引用问题

在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];
}
循环引用.png

NStimer 中的target 强引用 VC,VC强引用timer,互相持有,形成了一个循环圏,VC的dealloc永不会被执行,time也不被销毁,造成内存泄漏

解决方法

解决循环引用.png

使用中间类,让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,只看自己类里面有没有,如果没有直接进入消息转发,不会去父类里查找方法.

你可能感兴趣的:(解决NSTimer 循环引用问题)