[NSTimer scheduledTimerWithTimeInterval:4.0
target:self
selector:@selector(clickAction)
userInfo:nil
repeats:YES];
在项目里,这就是使用 NSTimer 最常用的方式 -- 在 vc 里定时或者延迟执行某个方法,可是又有多少个coder会想知道它和 Runloop 的关系?
当使用 NSTimer 的 scheduledTimerWithTimeInterval
方法时,事实上此时 NSTimer 会被加入到当前的 Runloop 中而且模式是默认的 NSDefaultRunLoopMode
。而如果当前线程就是主线程(UI线程), 在某些UI事件中,比如 UIScrollView 的拖动,会将 Runloop 切换成 NSEventTrackingRunLoopMode
模式,在这个过程中,默认的NSDefaultRunLoopMode
模式中注册的事件是不会被执行的。也就是说,此时使用 scheduledTimerWithTimeInterval
添加到 Runloop 中的 NSTimer 就不会执行。
实际需求:如何设置一个不被UI干扰的NSTimer?
需要手动创建一个 Timer,然后使用 NSRunLoop 的 addTimer:forMode:
方法来把 Timer 按照指定模式加入到 RunLoop 中。这里使用的模式是: NSRunLoopCommonModes
,这个模式等效于 NSDefaultRunLoopMode
和 NSEventTrackingRunLoopMode
的结合
示例 e.g
//创建Timer
NSTimer *timer = [NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(timer_callback) userInfo:nil repeats:YES];
//使用NSRunLoopCommonModes模式,把timer加入到当前Run Loop中。
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
NSTimer添加到Runloop中,但是不运行?
在iOS多线程中,每一个线程都有一个 Runloop,但是只有主线程的 Runloop 默认是打开的,其他子线程也就是我们创建的线程的 Runloop默认是关闭的,需要我们手动运行。我们可以通过 [NSRunLoop currentRunLoop]
来获得当前线程的 Runloop,并且调用
[runloop addTimer:timer forMode:NSDefaultRunLoopMode]
方法将定时器添加到 Runloop 中,最后一定不要忘记调用 Runloop 的 run
方法将当前 Runloop 开启,否则 NSTimer 永远也不会运行。
附录:苹果官方定义的Runloop的类型
网上看到比较好的文章记录:
- NSTimer和Runloop的关系 分析了平时使用NSTimer的注意点、实时性还有和 Runloop 的关系,特别是和 Runloop 的关系分析的挺细致的