项目中有时我们会遇见在滑动页面的时候,导致NSTimer停止的问题。如在滑动时,自己写的倒计时停止或者banner的定时滚动停止的情况。
此时的问题原因便是RunLoop
中的mode
类型未设置正确的mode类型。
在开启一个NSTimer实质上是在当前的runloop中注册了一个新的事件源,而当scrollView滚动的时候,当前的 MainRunLoop是处于UITrackingRunLoopMode
的模式下,在这个模式下,是不会处理NSDefaultRunLoopMode 的消息(因为RunLoop Mode不一样),要想在scrollView滚动的同时也接受其它RunLoop的消息,我们需要改变两者之间的RunLoopMode.
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
主线程的 RunLoop 里有两个预置的 Mode:kCFRunLoopDefaultMode 和 UITrackingRunLoopMode。这两个 Mode 都已经被标记为”Common”属性。DefaultMode 是 App 平时所处的状态
,TrackingRunLoopMode 是追踪 ScrollView 滑动时的状态
。当你创建一个 Timer 并加到 DefaultMode 时,Timer 会得到重复回调,但此时滑动一个TableView时,RunLoop 会将 mode 切换为 TrackingRunLoopMode,这时 Timer 就不会被回调,并且也不会影响到滑动操作。
这时你需要一个 Timer,在两个 Mode 中都能得到回调,一种办法就是将这个 Timer 分别加入这两个 Mode。还有一种方式,就是将 Timer 加入到顶层的 RunLoop 的 “commonModeItems” 中。”commonModeItems” 被 RunLoop 自动更新到所有具有”Common”属性的 Mode 里去。
CommonModes
一个 Mode 可以将自己标记为”Common”属性(通过将其 ModeName 添加到 RunLoop 的 “commonModes” 中)。每当 RunLoop 的内容发生变化时,RunLoop 都会自动将 _commonModeItems 里的 Source/Observer/Timer 同步到具有 “Common” 标记的所有Mode里。
网友评论