在使用NSTimer时,比较常见的问题:比如,如何初始化,两个初始化方法有什么不同?为什么我的NSTimer只执行了一次?为什么计时器会因为滑动暂停?
1),初始化的两个常用方法:timerWithTimeInterval和scheduledTimerWithTimeInterval
a)timerWithTimeInterval不会加到默认的RunLoop中,所以不会执行,需要自己调用:
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode]; [[NSRunLoop currentRunLoop] run]; //子线程中务必调用
这里注意,如果是在主线程中,那么不需要后面的run方法,因为主线程的RunLoop一直在运行,过了一个timeInterval之后就会执行了。但是在子线程中,runloop没有run起来,addTimer之后就结束,资源被收回了,所以不会执行。
b)scheduledTimerWithTimeInterval会加到NSDefaultRunLoopMode中。所以:
scheduledTimerWithTimeInterval = timerWithTimeInterval + [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode]
同上,子线程中也要自己来RunLoop run,否则也是不会执行的。
2),有时发现Timer虽然设置了repeats为YES,但是不执行,即使调用了fire也是只执行了一次。可能的原因就是在子线程中调用了,参见上一条。即RunLoop没有run,timer还没执行代码块就结束被回收了。所以这里要主动调用RunLoop run。
3),ScrollView等控件滚动的过程中会暂停。直接原因就是Timer的RunLoopMode不对,在NSDefaultRunLoopMode中的Timer会因为RunLoop切换Mode导致暂停。ScrollView滚动过程中会因为mode的切换,而导致NSTimer将不再被调度。
ScrollView滚动过程中NSDefaultRunLoopMode(kCFRunLoopDefaultMode)的mode会切换到UITrackingRunLoopMode来保证ScrollView的流畅滑动,NSTimer就暂停了。
RunLoop只能运行在一种mode下,如果要换mode,当前的loop也需要停下重启成新的。利用这个机制,ScrollView滚动过程中NSDefaultRunLoopMode(kCFRunLoopDefaultMode)的mode会切换到UITrackingRunLoopMode来保证ScrollView的流畅滑动:只能在NSDefaultRunLoopMode模式下处理的事件会影响ScrollView的滑动。
所以,不要使用scheduledTimerWithTimeInterval初始化,用timerWithTimeInterval初始化,然后
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];