記得自己剛接觸nstimer時,以為就是個定時循環執行某方法的計時器,然而之后遇到過各種問題,最近發現問的最多的就是頁面滑動時計時器不準的情況,下邊我總結一下自己長久以來收集到的信息.
1.基礎使用方法
非新手請自動濾過
/* NSTimer計時器類
TimeInterval:設定執行時間
target:目標
@selector:方法(也就是目標(target)的行為(selector))
userInfo:用于向selector方法中傳參數, 一般是self
repeats:是否重復
*/
NSTimer * timer = [NSTimer scheduledTimerWithTimeInterval:.9 target:self selector:@selector(changeColor:) userInfo:view4 repeats:YES];
[timer fire];//開始執行
//計時器執行的方法,sender 就是對應的計時器(那個計時器調的我)
- (void)changeColor:(NSTimer *)sender
{
//sender計時器對象,通過.userinfo屬性就能拿到當初傳來的參數(id類型),
對于此題上面穿的是一個view對象,所以直接用UIview類型接收
UIView * vie = sender.userInfo;
//修改傳入視圖的背景色
vie.backgroundColor = [UIColor colorWithRed:arc4random() % 256 / 255.0 green:arc4random() % 256 / 255.0 blue:arc4random() % 256 / 255.0 alpha:1.0];
}
2.開始和暫停
NSTimer 是木有暫停繼續的方法的,只有fire和invalidate,前者是開工的意思,后者是廢掉的意思,如果用廢掉來代替暫停的功能?顯然是不對的。
那腫么辦呢?
其實NSTimer 有一個屬性叫 fireDate ,啥意思呢?fireDate么,就是fire 的開始時間所以我們就有了思路了。
暫停: [timer setFireDate:[NSDate distantFuture]]; distantFuture,就是問你未來有多遠呢?好遠好遠就是無法到達的時間,所以 timer就一直等待不 fire了。也就是暫停了。
繼續: [timer setFireDate:[NSDate date]]; 這個當然就是把fire 的時間設置為當前時刻,所以timer就立刻開工啦!
3.解決滑動頁面計時器不準情況
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)yesOrNo;
在做界面滑動等操作時,計時器會不準
導致誤差的原因是我在使用“scheduledTimerWithTimeInterval”方法時,NSTimer實例是被加到當前runloop中的,模式是NSDefaultRunLoopMode。而“當前runloop”就是應用程序的main runloop,此main runloop負責了所有的主線程事件,這其中包括了UI界面的各種事件。當主線程中進行復雜的運算,或者進行UI界面操作時,由于在main runloop中NSTimer是同步交付的被“阻塞”,而模式也有可能會改變。因此,就會導致NSTimer計時出現延誤。
解決這種誤差的方法,一種是在子線程中進行NSTimer的操作,再在主線程中修改UI界面顯示操作結果;另一種是仍然在主線程中進行NSTimer操作,但是將NSTimer實例加到main runloop的特定mode(模式)中。避免被復雜運算操作或者UI界面刷新所干擾。
這里我經常用的是他:
[[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
[NSRunLoop currentRunLoop]獲取的就是“main runloop”,使用NSRunLoopCommonModes模式,將NSTimer加入其中。其他方法后續再補充.
比如我在自己寫的倒計時中就用到了這句:http://www.lxweimin.com/p/6ce30bd28fe7
關于runloop就比較高端了,我捉摸透了希望也可以總結下
未完待續