转,timer循环引用

当控制器ViewController跳转进入控制器OneViewController中的时候开启定时器,让定时器每隔一段时间打印一次,当OneViewController  dismiss的时候,控制器并没有被销毁.然而定时器的timer invalidate 在dealloc中已经写了.

如果没有定时器,则OneViewController可以正常销毁.

原因在于下图:循环引用

转,timer循环引用_第1张图片

控制器ViewController跳转进入OneViewController中开启定时器

#import"OneViewController.h"

@interfaceOneViewController()

@property(nonatomic,strong)NSTimer*timer;

@end

@implementationOneViewController

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent*)event {    

[self dismissViewControllerAnimated:YES completion:nil];

}

-(void)viewDidLoad

{    

[superviewDidLoad];

self.view.backgroundColor= [UIColororangeColor];

/**

1.__weak typeof(self) weakSelf = self; 不能解决

*///开启定时器self.timer= [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector( testTimerDeallo ) userInfo:nil repeats:YES];

}/** 方法一直执行 */

-(void) testTimerDeallo

{

NSLog(@"-----");

}

当开启定时器以后,testTimerDeallo方法一直执行,即使dismiss此控制器以后,也是一直在打印,而且dealloc方法不会执行.循环引用造成了内存泄露,控制器不会被释放.

/** 开启定时器以后控制器不能被销毁,此方法不会被调用 */

-(void)dealloc

{NSLog(@"xiaohui");   

 [self.timerinvalidate];}

@end

解决办法: 由于循环引用的起因是target,则可以包装一个target,让target是另一个对象,而不是ViewController即可.

1.创建一个集成NSObject的子类TimerWeakTarget,创建类方法---开启定时器的方法

#import@interfaceTimerWeakTarget:NSObject

@property(nonatomic,assign) SEL selector;

@property(nonatomic,weak)NSTimer*timer;

@property(nonatomic,weak) id target;/**

1.重写开启定时器方法,在内部对target进行替换,换成本类(TimerWeakTarget)的对象即可

2.不会造成循环引用了,原控制器OneViewController属性有timer对timer强应用,timer内部对self强引用,但是self在此方法内部被替换成了本类的对象(TimerWeakTarget *),而本类的对象不会对OneViewController强引用,则不会造成循环引用,也就不会造成内存泄露

*/+ (NSTimer*) scheduledTimerWithTimeInterval:(NSTimeInterval)interval                                      target:(id)aTarget                                    selector:(SEL)aSelector                                    userInfo:(id)userInfo                                    repeats:(BOOL)repeats;@end

TimerWeakTarget.m文件中

在下面我们封装的类的方法中,我们将开启定时器的方法 [NSTimer scheduledTimerWithTimeInterval:interval target:timer selector:@selector(fire:) userInfo:userInfo repeats:repeats];中的target换掉了,换成了 本类的对象,timer.在OneViewController中开启定时器的时候直接调用这个类方法,就不会造成循环引用.看图

转,timer循环引用_第2张图片

#import"TimerWeakTarget.h"

@implementationTimerWeakTarget

+ (NSTimer*) scheduledTimerWithTimeInterval:(NSTimeInterval)interval                                      target:(id)aTarget                                    selector:(SEL)aSelector                                    userInfo:(id)userInfo                                    repeats:(BOOL)repeats{    TimerWeakTarget * timer = [TimerWeakTarget new];    

timer.target= aTarget;    

timer.selector= aSelector;//-------------------------------------------------------------此处的target已经被换掉了不是原来的VIewController而是TimerWeakTarget类的对象timertimer.timer= [NSTimerscheduledTimerWithTimeInterval:interval target:timer selector:@selector(fire:) userInfo:userInfo repeats:repeats];returntimer.timer;}

-(void)fire:(NSTimer*)timer{if(self.target)

 {        [self.targetperformSelector:self.selectorwithObject:timer.userInfo];    }else{        [self.timerinvalidate];    }}

@end

控制器dismiss以后可以正常被销毁.问题解决.

文/AlexPei(作者)

原文链接:http://www.jianshu.com/p/a51c6dd12587

著作权归作者所有,转载请联系作者获得授权,并标注“作者”。

你可能感兴趣的:(转,timer循环引用)