NSTimer
NSTimer 常用的兩種創(chuàng)建方式
+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo;
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo;
第一種方式
通過 timerWith… 方法創(chuàng)建的 timer 驼鹅,需要手動添加到 runloop 中微谓,否則不會啟動。
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:3.0 target:self selector:@selector(show) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
第二種方式
通過 scheduleTimerWith… 方法創(chuàng)建的 timer输钩,會默認被添加到 runloop 的NSDefaultRunLoopMode
中豺型,我們可以手動修改 runloop 的模式。
NSTimer *timer = [NSTimer timerWithTimeInterval:3.0 target:self selector:@selector(show) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
timer不準的原因
模式的改變
主線程的 runloop 里有兩個預(yù)置的Mode:NSDefaultRunLoopMode
和 UITrackingRunLoopMode
买乃。
當(dāng)創(chuàng)建一個 timer 并添加到 defaultMode 時姻氨,timer會得到重復(fù)回調(diào)。但此時滑動一個scrollview剪验,RunLoop 會將 mode 切換到 UITrackingRunLoopMode哼绑,這時 timer 不會被回調(diào),并且也不會影響到滑動操作碉咆。所以會導(dǎo)致NSTimer不準的情況抖韩。
解決方案:
定時器添加到 runloop 的 NSRunLoopCommonModes
模式中,該模式是以上兩種模式的組合疫铜。
線程阻塞
timer 觸發(fā)時茂浮,如果 runloop 在阻塞狀態(tài),timer 的觸發(fā)會推遲到下一個 runloop 周期壳咕,導(dǎo)致延遲席揽。
dispatch_source 實現(xiàn)高精度定時器
GCD 實現(xiàn)的定時器不受 runloop 模式的影響,使用 dispatch_source 能夠?qū)崿F(xiàn)沒有延遲的定時器谓厘。
dispatch_queue_t queue1 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue1);
self.timer = timer;
dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 3 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
dispatch_source_set_event_handler(timer, ^{
NSLog(@"%@",[NSThread currentThread]);
});
dispatch_resume(timer);
CADisplayLink
能保證和屏幕刷新率相同的頻率幌羞,將特定的內(nèi)容畫到屏幕上。
CADisplayLink 以特定的模式的添加到 runloop 后竟稳,每當(dāng)屏幕需要刷新時属桦,runloop 就會像 target 發(fā)送 selector 消息熊痴。所以 displayLink 的時間間隔是和屏幕刷新頻率相關(guān)聯(lián)的。
CADisplayLink *link = [CADisplayLink displayLinkWithTarget:self selector:@selector(test)];
[link addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];