解决方法增加timer的runloop模式:
[[NSRunLoop currentRunLoop] addTimer:timer forMode:UITrackingRunLoopMode]; 或
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
原因分析:
NSTImer的实现时基于runLoop的,而runloop又有以下5种模式,某一时刻只能处理对应模式下的事件。
- Default模式
定义:NSDefaultRunLoopMode (Cocoa) kCFRunLoopDefaultMode (Core Foundation)
描述:默认模式中几乎包含了所有输入源(NSConnection除外),一般情况下应使用此模式。 - Connection模式
定义:NSConnectionReplyMode(Cocoa)
描述:处理NSConnection对象相关事件,系统内部使用,用户基本不会使用。 - Modal模式
定义:NSModalPanelRunLoopMode(Cocoa)
描述:处理modal panels事件。 - Event tracking模式
定义:UITrackingRunLoopMode
(iOS) NSEventTrackingRunLoopMode(cocoa)
描述:在拖动loop或其他user interface tracking loops时处于此种模式下,在此模式下会限制输入事件的处理。例如,当手指按住UITableView拖动时就会处于此模式。 - Common模式
定义:NSRunLoopCommonModes (Cocoa) kCFRunLoopCommonModes (Core Foundation)
描述:这是一个伪模式,其为一组run loop mode的集合,将输入源加入此模式意味着在Common Modes中包含的所有模式下都可以处理。在Cocoa应用程序中,默认情况下Common Modes包含default modes,modal modes,event Tracking modes.可使用CFRunLoopAddCommonMode方法想Common Modes中添加自定义modes。
获取当前线程的run loop mode:
NSString* runLoopMode = [[NSRunLoopcurrentRunLoop]currentMode];
NSTimer默认处于NSDefaultRunLoopMode,在没有滚动时,runloop处于NSDefaultRunLoopMode下,滚动时处于UITrackingRunLoopMode,导 致NSTimer事件源被过滤了,所以不执行,那怎么办,只需要给NSTimer再添加一个模式:
[NSRunLoop currentRunLoop] addTimer:timer forMode:UITrackingRunLoopMode]或
干脆就所有模式下都能执行:
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];