问题描述:
当你使用Timer时,特别repeat时,你的Timer所在类往往无法调用dealloc,也就该类一直有strong reference指向它(使它无法被释放,造成内存泄露)。
问题原理探究:
当你schedule你的timer到runloop时,runloop会对timer持有强引用。而Timer会对它的target或都invocation持有强引用。
runloop --->(strong) timer ---->(strong) target or invocation
在你的timer invalidate之前你的target会一直无法被释放,不管你的target 对timer是持有强引用还是弱引用。强引用的话就是strong reference circle。
解决方案
- 你能确保一定会把你的timer invalidate掉。
- 如果你无法确保一定会invalidate你的tiemr。就需要引入第三个类,来打破强引用:
@interface MyClassTimerDeliver : NSObject
@property (nonatomic, weak) id delegate;
- (void)renderExpiredCountdown:(id)sender;
@end
@implementation MyClassTimerDeliver
- (void)renderExpiredCountdown:(id)sender {
if([self.delegaterespondsToSelector:@selector(renderExpiredCountdown:)]) {
[self.delegateperformSelector:@selector(renderExpiredCountdown:) withObject:nil];
}
}
@end
@interface MyClass : SomeSuperClass {
NSTimer *_timer;
}
@property (nonatomic, strong) MyClassTimerDeliver *timerDeliver;
@end
@implementation MyClass
- (void)dealloc {
if (_timer) {
[_timerinvalidate];
_timer = nil;
}
}
- (void)doTimer {
// code here actually do the tiemr
}
- (void)renderExpiredCountdown:(id)sender {
[_timeDeliver.delegatedoTimer];
}
- (void)createTimer {
_timeDeliver = [[MDMyLotteryDataSourceTimerDeliveralloc] init];
_timeDeliver.delegate = self;
//只创建一个定时器NSTimer
if (!_timer) {
_timer = [NSTimerscheduledTimerWithTimeInterval:1.0target:_timeDeliverselector:@selector(renderExpiredCountdown:) userInfo:nilrepeats:YES];
[[NSRunLoopcurrentRunLoop] addTimer:_timerforMode:NSRunLoopCommonModes];//解决滚动的时候计时器就会停止
}
}
@end