定時(shí)器,相信大家都不會(huì)陌生瓢剿,開發(fā)中經(jīng)常會(huì)遇到逢慌,最常見的廣告頁、計(jì)時(shí)等跋选。當(dāng)然了這些都不是大問題涕癣,但是有時(shí)候如果注意的話,相信大家都會(huì)遇到一個(gè)問題前标,定時(shí)器好好的執(zhí)行著我們的一些操作的時(shí)候坠韩,如果我們這時(shí)候有UI操作(比如滾動(dòng)界面),我們會(huì)發(fā)現(xiàn)好像沒定時(shí)器一樣炼列,但是UI操作結(jié)束時(shí)只搁,定時(shí)器又會(huì)重新工作。相信大家第一時(shí)間都會(huì)想到RunLoop俭尖。
說到定時(shí)器失效談到了RunLoop氢惋,那我們先來創(chuàng)建定時(shí)器。其實(shí)創(chuàng)建定時(shí)器的方法有好幾種稽犁,這里我們所以下做常用到的三種方法焰望。其實(shí)也可以說成是兩種,NSTimer分成了類方法創(chuàng)建和對(duì)象方法創(chuàng)建已亥。
1熊赖、
[NSTimer scheduledTimerWithTimeInterval:1 repeats:YES block:^(NSTimer * _Nonnull timer) {
NSLog(@"%ld",++self.page);
}];
這種類方法創(chuàng)建定時(shí)的一點(diǎn)好處就是不用我們把定時(shí)器添加到RunLoop上,但是好像跟今天的這個(gè)問題就解決不了了虑椎。(好像是的可能這點(diǎn)我也理解的不太清楚震鹉,因?yàn)槭穷悾翘砑覴unLoop上的是NSTimer的對(duì)象)捆姜。
2传趾、用NSTimer的對(duì)象方法創(chuàng)建
NSTimer *timer = [[NSTimer alloc]initWithFireDate:[NSDate distantPast] interval:1 target:self selector:@selector(timerAction:) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop]addTimer:timer forMode:NSDefaultRunLoopMode];
這種方式要想定時(shí)器工作,必須要把定時(shí)器添加到RunLoop的上泥技,而我們一般做的就是講定時(shí)器添加到默認(rèn)模式上的浆兰。
3、相信大家試過的都知道用上面兩種方法創(chuàng)建就會(huì)出現(xiàn)上圖所示的問題零抬。但是用下面的方法創(chuàng)建的話就不會(huì)出現(xiàn)镊讼。GCD創(chuàng)建定時(shí)器:
dispatch_queue_t myQuest = dispatch_get_main_queue();
self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, myQuest);//這里要將定時(shí)器設(shè)為全局,否則定時(shí)器將不會(huì)啟動(dòng)平夜。
dispatch_source_set_timer(self.timer, DISPATCH_TIME_NOW, 1.0 * NSEC_PER_SEC, 1.0 * NSEC_PER_SEC);
dispatch_source_set_event_handler(self.timer, ^{
NSLog(@"%ld,--%@--",++self.page,[NSRunLoop currentRunLoop]);
});
dispatch_resume(self.timer);
GCD中的單位是納秒NSEC_PER_SEC這個(gè)宏可以點(diǎn)進(jìn)去看一下是1000000000蝶棋,這個(gè)蘋果已經(jīng)為我們做好了不用管,就按照我們平時(shí)的那種做法多少秒就寫幾就好了忽妒。
實(shí)驗(yàn)發(fā)現(xiàn)玩裙,用NSTimer創(chuàng)建兼贸,要解決定時(shí)器失效的問題,要將定時(shí)器添加到UI模式下:UITrackingRunLoopMode和NSDefaultRunLoopMode下才可以吃溅,通常直接寫NSRunLoopCommonModes(包含了UI和默認(rèn)模式)才可以解決定時(shí)器失效的問題溶诞,而用GCD寫的話就不用了,其實(shí)GCD也用只不過蘋果幫我們封裝好了决侈,不用我們自己寫了螺垢。
相信好多人不知道為什么回事這樣的效果,原因是什么赖歌。
RunLoop運(yùn)行循環(huán)枉圃,我們也可以叫做死循環(huán),其實(shí)我們就可以把他當(dāng)做是一個(gè)傭人(程序的傭人)庐冯;
每一個(gè)程勛都有一個(gè)RunLoop孽亲,我們的操作都是由他來幫我們實(shí)現(xiàn)的RunLoop總共有五種模式,只不過我們用到的只有上面三種展父。
每一個(gè)模式下有souce,obsever,Timer三個(gè)服務(wù)(優(yōu)先級(jí)從高到低)返劲;而我們的Timer就是在這里被執(zhí)行的,平常的時(shí)候我們?cè)谀J(rèn)模式下栖茉,RunLoop就會(huì)幫我們執(zhí)行篮绿,但是有一些UI操作時(shí),這時(shí)候RunLoop已經(jīng)切換到UI模式了吕漂,因?yàn)閁I模式的優(yōu)先級(jí)比默認(rèn)模式的優(yōu)先級(jí)高搔耕,所以有一些滑動(dòng)操作時(shí),RunLoop就會(huì)去執(zhí)行痰娱,因?yàn)槊總€(gè)應(yīng)用程序只有一個(gè)RunLoop所以我們默認(rèn)模式下的timer就不會(huì)工作了,所以我們想菩收,RunLoop既然去為為UI模式工作了梨睁,那我們就把定時(shí)器放到UI模式下就可以了,事實(shí)證明真的如此娜饵。
有的人在想坡贺,那我們剛一開始就把timer直接放在UI模式下,這樣做的話你會(huì)發(fā)現(xiàn)箱舞,跑起來的時(shí)候定時(shí)器也沒起作用遍坟,只有在滑動(dòng)界面的時(shí)候才會(huì)起作用。因?yàn)橹挥性谧鲆恍︰I操作時(shí)才會(huì)觸發(fā)RunLoop的UI模式晴股,平常的時(shí)候是沒有用的愿伴。所以我們一般就會(huì)把timer放在默認(rèn)和UI模式下,這樣不管正常還是UI滑動(dòng)界面時(shí)都不會(huì)使定時(shí)器失效电湘「艚冢可以看一下圖更清晰:
有什么不對(duì)的地方請(qǐng)大家指正鹅经。或者誰有更好的理解怎诫。