一、问题产生与分析
先看下产生的代码:
- (void)dealloc{ [self.timer invalidate]; self.timer = nil; NSLog(@"dealloc!!!!!!!");}- (void)viewDidLoad{ [super viewDidLoad]; self.timer = [NSTimer scheduledTimerWithTimeInterval:3.0f target:self selector:@selector(timerFire) userInfo:nil repeats:YES]; [self.timer fire];}- (void)timerFire{ NSLog(@"fire");}在这段代码,你在dealloc处放置一个breakpoint,你会发现dealloc方法不会执行的。因为此时存在着一个引用循环:
每个NSTimer其实是被添加在所在线程的runloop中,而runloop对timer是一种强持有关系,看下苹果官网:
也就是说,此时的timer采取strong PRoperty的方式其实是不合理的。那么为什么Runloop要strong reference to a timer呢,首先,NSTimer的执行需要加到runloop中去。RunLoop有一个CFRunLoopTimerRef 是基于时间的触发器的类,它和 NSTimer 是toll-free bridged 的,可以混用。其包含一个时间长度和一个回调(函数指针)。当其加入到 RunLoop 时,RunLoop会注册对应的时间点,当时间点到时,RunLoop会被唤醒以执行那个回调(这就是为什么要强持有target)。
二、解决方法
1、及时invalidate()掉Timer
invalidate()的作用,苹果有描述 :
执行之后,Runloop对Timer的强引用就会remove掉,同时timer对target的强引用也会remove掉,通过CFGetRetainCount()方法查看self的引用即可知道,验证如下:
NO Repeats的Timer是会自动invalidate()的,所以,invalidate()后timer仅仅是self的一个属性变量了。
对于Repeats类型的Timer需要在合适的时机去手动invalidate()了,例如在viewDidDisappear方法中,就是一种不错的尝试。
2、不需要手动设置NSTimer为invalid 的方法:造一个假的target给NSTimer,假的target作用就是用于接受NSTimer的强引用。
具体的思路代码,如下:
[...]@implementation NSWeakTimerTarget{ __weak target; SEL selector;}[...] - (void)timerDidFire:(NSTimer *)timer{ if (target) { [target performeSelector:selector withObject:timer]; } else { [timer invalidate]; }}@end @implementation NSWeakTimer + (NSTimer *)scheduledTimerWithTimerInterval:(NSTimeInterval)ti target:(id)target selector:(SEL)aSelector userInfo:(id)userInfo repeat:(BOOL)repeats{ NSWeakTimerTarget *timerTarget = [[NSWeakTimerTarget alloc] init] timerTarget.target = aTarget; timerTarget.selector = aSelector; timerTarget.timer = [NSTimer scheduledTimerWithTimeInterval:ti target:timerTarget selector:@selector(timerDidFire:) userInfo: userInfo repeats: repeats]; return timerTarget.timer;}@end此法真正的target并不会被timer 持有,当真正的target为空的时候,timer会执行invalid。此法的github地址:https://github.com/ChatGame/HWWeakTimer三、参考资料
1、https://developer.apple.com/reference/foundation/timer/1415405-invalidate?changes=latest_minor
2、http://www.jianshu.com/p/f9999b5958f8
新闻热点
疑难解答