在之前的一些项目中,我们曾经遇到过一个问题:在进行秒杀活动时,我们需要在页面上显示活动的倒计时。为了实现这个功能,我们使用了`+scheduledTimerWithTimeInterval:`方法创建了一个定时器(NSTimer)。然而,当我们在滑动列表时,发现定时器暂停了,页面上的倒计时也停止了。
经过深入研究NSTimer的运行原理,我们发现NSTimer与RunLoop有关。实际上,RunLoop与线程密切相关,这里就不详细展开了。RunLoop只能运行在一种模式下,如果要切换到另一种模式,当前的循环也需要停止并重新启动为新的模式。利用这个机制,当ScrollView滚动时,NSDefaultRunLoopMode(kCFRunLoopDefaultMode)的模式会切换到UITrackingRunLoopMode,以保证ScrollView的流畅滑动;只有在NSDefaultRunLoopMode模式下处理的事件会影响ScrollView的滑动。
如果我们将一个NSTimer对象添加到主运行循环的NSDefaultRunLoopMode(kCFRunLoopDefaultMode)中,那么在ScrollView滚动过程中,由于模式的切换,NSTimer将不再被调度。但是,因为模式仍然是可定制的,所以我们可以通过将timer添加到NSRunLoopCommonModes(kCFRunLoopCommonModes)来解决这个问题。以下是相应的代码:
```objc
// 创建一个NSTimer对象
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerAction) userInfo:nil repeats:YES];
// 将timer添加到NSRunLoopCommonModes(kCFRunLoopCommonModes)中
[NSRunLoop addTimer:timer forMode:NSRunLoopCommonModes beforeDate:[NSDate date]];
```
通过这种方式,我们可以避免定时器受到ScrollView滚动的影响,从而实现活动的倒计时功能。