當控制器ViewController跳轉進入控制器OneViewController中的時候開啟定時器,讓定時器每隔一段時間打印一次,當OneViewController? dismiss的時候,控制器并沒有被銷毀.然而定時器的timer invalidate 在dealloc中已經寫了.
如果沒有定時器,則OneViewController可以正常銷毀.
原因在于下圖:循環引用
控制器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中開啟定時器的時候直接調用這個類方法,就不會造成循環引用.看圖
#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.lxweimin.com/p/a51c6dd12587
著作權歸作者所有,轉載請聯系作者獲得授權,并標注“簡書作者”。