如何优雅的解决NSTimer释放问题

  NSTimer放在dealloc中进行销毁,退出页面后计数器仍然会存在。这是因为实例对象引用了timer,而timer目标对象是self,退出页面实例对象并没有销毁,dealloc方法没有调用,导致NSTimer也就没有释放。
  大多数时候我也会放在- (void)viewWillAppear:(BOOL)animated启动定时器,在- (void)viewWillDisappear:(BOOL)animated释放定时器。这能解决大多数问题,但如果你是在view中启动的定时器呢,需要在viewController中调用其销毁方法了,这使得代码不够优雅,同时释放时机不对,还可能造成提前释放或没有释放。
  其实了解了NSTimer没有释放的原因,我们就能很好的解决这个问题。NSTimer的循环引用和block是一样的。我们可以用NSTimer的分类和__weak来解决这个问题:
1.新建NSTimer一个分类,改变target的目标对象,添加下面代码:

@interface NSTimer (Weak)
+ (NSTimer *)eoc_scheduledTimerWithTimerInterval:(NSTimeInterval)interval block:(void(^)(void))block repeats:(BOOL)repeats;
@end

@implementation NSTimer (Weak)
+ (NSTimer *)eoc_scheduledTimerWithTimerInterval:(NSTimeInterval)interval block:(void(^)(void))block repeats:(BOOL)repeats{
    return [self scheduledTimerWithTimeInterval:interval target:self selector:@selector(eoc_blockInvoke:) userInfo:[block copy] repeats:repeats];
}

+ (void)eoc_blockInvoke:(NSTimer *)timer{
    void (^block)(void) = timer.userInfo;
    if (block) {
        block();
    }
}

@end

  这样timer的Target是NSTimer类对象,这是个单例,因此计时器是否会保留它,其实都无所谓。
2.启动定时器

__weak typeof(self) weakSelf = self;
    self.timer = [NSTimer eoc_scheduledTimerWithTimerInterval:1.0 block:^{
        [weakSelf tickWithAnimation:YES];
    } repeats:YES];

  注意block的循环引用
3.在dealloc中销毁定时器

- (void)dealloc{
    [self.timer invalidate];
    self.timer = nil;
}

  这一步就算忘记写了,[weakSelf tickWithAnimation:YES];退出页面后weakSelf也是nil。定时器在运行,也不会再调用tickWithAnimation方法了。

总结:
1.其实定时器不能释放的原理和block一样,都是循环引用造成的,我们只要想办法断开循环应用的环,内存泄露的问题就能很好的解决。
2.文中的方法可以是通用的,我们可以在dealloc中释放定时器,这样只要引用timer的实例销毁了,timer也会跟着销毁,我们就不用担心释放的时机不对。
3.有任何问题欢迎留言交流。

你可能感兴趣的:(如何优雅的解决NSTimer释放问题)