-
當控制器ViewController跳轉進入控制器OneViewController中的時候開啟定時器,讓定時器每隔一段時間打印一次,當OneViewController dismiss的時候,控制器並沒有被銷毀.然而定時器的timer invalidate 在dealloc中已經寫了.
-
如果沒有定時器,則OneViewController可以正常銷毀.
-
原因在於下圖:循環引用
-
控制器ViewController跳轉進入OneViewController中開啟定時器
#import "OneViewController.h"
@interface OneViewController ()
@property (nonatomic, strong) NSTimer *timer;
@end
@implementation OneViewController
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
[self dismissViewControllerAnimated:YES completion:nil];
}
-(void)viewDidLoad{
[super viewDidLoad];
self.view.backgroundColor = [UIColor orangeColor];
/**
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.timer invalidate];
}
@end
- 解決辦法: 由於循環引用的起因是target,則可以包裝一個target,讓target是另一個對象,而不是ViewController即可.
- 1.創建一個集成NSObject的分類TimerWeakTarget,創建類方法---開啟定時器的方法
#import <Foundation/Foundation.h>
@interface TimerWeakTarget : 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"
@implementation TimerWeakTarget
+ (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類的對象timer
timer.timer = [NSTimer scheduledTimerWithTimeInterval:interval target:timer selector:@selector(fire:) userInfo:userInfo repeats:repeats];
return timer.timer;
}
-(void)fire:(NSTimer *)timer{
if (self.target) {
[self.target performSelector:self.selector withObject:timer.userInfo];
} else {
[self.timer invalidate];
}
}
@end
- 控制器dismiss以后可以正常被銷毀.問題解決.