iOS【NSTimer到底準(zhǔn)不準(zhǔn)拌禾?】
2018.2.1 ?最近面試 被 問道 NSTimer 到底準(zhǔn)不準(zhǔn)的問題 當(dāng)時(shí)有點(diǎn)蒙 因?yàn)闆]爬過這個(gè)坑 所以沒法打出來 特此記錄一下
當(dāng)時(shí) 就知道 人家 問了 ?那么就說明 NSTimer 一定是不準(zhǔn)的 但是 ?問題點(diǎn)就是 在這個(gè) 準(zhǔn)不準(zhǔn)的標(biāo)準(zhǔn)是什么呢 ? ?
定時(shí)器 很簡單 ?回來后做了個(gè)測試 ?自己寫了個(gè) 定時(shí)器?
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
? ? if (!_timer) {
? ? ? ? _timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(logInfo) userInfo:nil repeats:YES];
? ? }
}
- (void)logInfo {
? ? NSLog(@"timer test");
}
?結(jié)果是?
2018-02-01 09:12:32.566622+0800 QTimer[20276:7878806] timer test
2018-02-01 09:12:33.566811+0800 QTimer[20276:7878806] timer test
2018-02-01 09:12:34.566510+0800 QTimer[20276:7878806] timer test
2018-02-01 09:12:35.567532+0800 QTimer[20276:7878806] timer test
2018-02-01 09:12:36.567613+0800 QTimer[20276:7878806] timer test
2018-02-01 09:12:37.566615+0800 QTimer[20276:7878806] timer test
2018-02-01 09:12:38.567415+0800 QTimer[20276:7878806] timer test
2018-02-01 09:12:39.567650+0800 QTimer[20276:7878806] timer test
2018-02-01 09:12:40.566592+0800 QTimer[20276:7878806] timer test
可以看出來 ?定時(shí)器 并不是準(zhǔn)確的 ?1S的 ?誤差 在 1毫秒以內(nèi) ?應(yīng)該是很準(zhǔn)的了
但是 確實(shí) 是不準(zhǔn)的 ? ?我們繼續(xù) 給 定時(shí)器 的方法里面 繼續(xù) 添加更多的耗時(shí)代碼;
- (void)logInfo {
? ? int count = 0;
? ? for (int i = 0; i < 1000000000; i++) {
? ? ? ? count += i;
? ? }
? ? NSLog(@"timer test");
}
結(jié)果
2018-02-01 09:40:38.194879+0800 QTimer[9749:3330951] timer test
2018-02-01 09:40:44.188463+0800 QTimer[9749:3330951] timer test
2018-02-01 09:40:50.172012+0800 QTimer[9749:3330951] timer test
2018-02-01 09:40:56.172139+0800 QTimer[9749:3330951] timer test
2018-02-01 09:41:02.179022+0800 QTimer[9749:3330951] timer test
2018-02-01 09:41:08.170254+0800 QTimer[9749:3330951] timer test
2018-02-01 09:41:14.169011+0800 QTimer[9749:3330951] timer test
可以清晰的看出來 時(shí)間已經(jīng)不準(zhǔn)的 準(zhǔn)確的來說 ?那么原因是什么呢 經(jīng)過 查找資料得知
定時(shí)器被添加在主線程中,由于定時(shí)器在一個(gè)RunLoop中被檢測一次匪傍,所以如果在這一次的RunLoop中做了耗時(shí)的操作,當(dāng)前RunLoop持續(xù)的時(shí)間超過了定時(shí)器的間隔時(shí)間茵休,那么下一次定時(shí)就被延后了手蝎。
意思就是說 ?你這個(gè) 定時(shí)器的方法里面 相當(dāng)于 一個(gè)runloop ?只有當(dāng) 方法 里面代碼 走完了 定時(shí)器 才會 繼續(xù) 起作用 就是說 ?當(dāng) ?定時(shí)器 方法 里面 的耗時(shí)操作 超過了 定時(shí)器的時(shí)間間隔 ?那么 就會 導(dǎo)致 定時(shí)方法里面的代碼 執(zhí)行之后 ?才會繼續(xù)定時(shí)器 再間隔一s 之后執(zhí)行這個(gè)方法 (這個(gè)情況 會出現(xiàn)的 前提是 定時(shí)器里面的方法 的耗時(shí)操作 超過了 定時(shí)的 時(shí)間間隔);
接下來就是 解決方法了 ?既然 執(zhí)行方法 會 阻礙NSTtimer ?那么我們就把他們分開 ?
解決方法:
1棵介、在子線程中創(chuàng)建timer,在主線程進(jìn)行定時(shí)任務(wù)的操作
2唠雕、在子線程中創(chuàng)建timer岩睁,在子線程中進(jìn)行定時(shí)任務(wù)的操作锐极,需要UI操作時(shí)切換回主線程進(jìn)行操作
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(newThread)object:nil];2[thread start];
- (void)newThread2{
?@autoreleasepool
?{
[NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(addTime) userInfo:nil repeats:YES];
?[[NSRunLoop currentRunLoop] run];
?}
}
在子線程中將NSTimer以默認(rèn)方式加到該線程的runloop中,啟動(dòng)子線程肋层。(注意 timer 的runloop 模式的形象 因?yàn)槭窃谧泳€程里面 所以 runloop的model 沒考慮 如果特殊情況 考慮runloop的model ?就不采用 默認(rèn)的方式創(chuàng)建timer 手動(dòng)添加 到runloop 里面 去 采用commodmodel )
或者干脆 直接用多線程GCD 定時(shí)器 ?也是 多線程方式 ?回歸主線程 刷新UI?