iOS 一个NSTimer引起的内存泄漏问题

老早就听说NSTimer会在界面进行滑动时卡顿或停住,由于从来没有碰见过(。。。。),所以就想验证一下。在一个空白控制器界面添加一个UIScrollView对象backView,创建一个定时器changeTimer,执行方法changeColorAction,每隔1秒钟修改视图backView的背景颜色。测试可见在上下拖动或拖拽不放时,定时器都会停止不再执行,即backView的颜色不再改变,松开后定时器又开始继续执行。
下面这两个方法创建定时器,文档的说明

Creates a timer and schedules it on the current run loop in the default mode.

就是在run loop中添加一个default mode的timer,这个default mode就是NSDefaultRunLoopMode,没有滑动事件的优先级(NSRunLoopCommonModes)高,所以就会产生timer停住的情况。

[NSTimer scheduledTimerWithTimeInterval:1.0 repeats:YES block:^(NSTimer * _Nonnull timer) {
}];
[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(changeColorAction) userInfo:nil repeats:YES];

想要同时滑动和执行定时器任务,就需要修改定时器的mode。

[[NSRunLoop mainRunLoop] addTimer:changeTimer forMode:NSRunLoopCommonModes];

这个定时器停止的问题貌似已经研究好了,但是从测试界面一返回,发现控制器并没有走dealloc方法(在基类中重写的),控制台没打印信息,难道就这一点代码还发生循环引用了?
查看方法scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:的说明发现在描述target参数是这样写的:

The object to which to send the message specified by aSelector when the timer fires. The timer maintains a strong reference to target until it (the timer) is invalidated.

原来timer会对他的target做一个强引用,直到调用timer的invalidate方法。接着就在控制器中写下了很2的代码,

- (void)dealloc
{
    [self.changeTimer invalidate];
}

发现这样写界面返回后控制器仍旧不走dealloc方法。
timer调用invalidate才会不再强引用target,那不是说timer调用invalidate方法后控制器才有可能走dealloc方法么?。。。。换到控制器viewDidDisappear方法中调用,才得以处理。

- (void)viewDidDisappear:(BOOL)animated
{
    [super viewDidDisappear:animated];
    [self.changeTimer invalidate];
}

随后检查了之前的代码,在用户获取验证码界面,确实会出现内存泄漏问题,因为只在倒计时结束时调用了timer的invalidate方法。增加了在控制器viewDidDisappear方法中调用timer的invalidate方法代码。放在viewWillAppear方法中也试了,明显是不对的,一旦用户侧滑一点timer就会停止。
之前判断一个界面中是否发生循环引用,就简单的看了控制台是否打印了控制器走dealloc方法的信息。控制器界面返回后走了dealloc方法,这个界面里就一定没有内存泄漏了么?

猜你喜欢

转载自blog.csdn.net/Mr17Liu/article/details/81867369