NSTimer時(shí)鐘事件:
一般情況 我們會(huì)這樣擼
[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timeMethod) userInfo:nil repeats:YES];
- (void)timeMethod{
? ? NSLog(@"timeMethod來(lái)了");
}
//這個(gè)時(shí)候 timeMethod來(lái)了每秒鐘會(huì)打印一次
好問(wèn)題來(lái)了,這個(gè) 時(shí)候我拖一個(gè)UITextView放到控制器许蓖,當(dāng)我們一直拖動(dòng)UITextView的時(shí)候,“ timeMethod來(lái)了每秒鐘會(huì)打印一次”是不是停下來(lái)了。
為什么乱凿?
--首先我們要搞清楚因块,NSTimer事件是交給誰(shuí) 處理殴玛?--"Runloop"在處理,系統(tǒng)會(huì)把這個(gè)事件包裝成“souce”事件源給RunLoop處理束析;
那RunLoop在處理這些事件的時(shí)候有什么區(qū)分和區(qū)別呢?
--是有的憎亚,從下面兩個(gè)圖可以看出Runloop處理事件會(huì)有優(yōu)先級(jí)的员寇,UI模式級(jí)別最高弄慰,所有當(dāng)我們拖動(dòng)UITextView的時(shí)候,RunLoop在處理UITextView的觸摸事件(這個(gè)事件是UI模式下的事件 )蝶锋,timeMethod來(lái)了沒(méi)有打印了
好現(xiàn)在我們來(lái)做個(gè)試驗(yàn)陆爽,假設(shè)我們想要在觸摸UI 的時(shí)候,Timer事件還是會(huì)被處理扳缕,那我們添加到RunLoopd的UI模式下
??? NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(timeMethod) userInfo:nil repeats:YES];
???
??? //UITrackingRunLoopMode
??? [[NSRunLoop currentRunLoop] addTimer:timer forMode:UITrackingRunLoopMode];
奇怪了慌闭,這個(gè)時(shí)候只有在觸摸UI的時(shí)候才會(huì)打印,
其實(shí):
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timeMethod) userInfo:nil repeats:YES];
等同于下面的默認(rèn)模式躯舔,觸摸UI的時(shí)候RunLoop不會(huì)處理UI模式下的事件
NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(timeMethod) userInfo:nil repeats:YES];
? ? //UITrackingRunLoopMode
? ? [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
如果我們想普通模式和UI模式下驴剔,都有事件響應(yīng),那邊我們需要把這個(gè)Timer添加到第3中模式粥庄,站位模式"NSRunLoopCommonModes"
//總共有5中模型 UI 默認(rèn) 占位模式(默認(rèn)&UI模式) 程序啟動(dòng)模式 內(nèi)核模式
NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(timeMethod) userInfo:nil repeats:YES];
? ? [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
以為站位模式就萬(wàn)事大吉了沒(méi)仔拟,NO,避免我們這個(gè)Timer做一個(gè)耗時(shí)操作飒赃,運(yùn)行下面代碼(在timeMethod讓線程睡2秒)
NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(timeMethod) userInfo:nil repeats:YES];
? ? [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
- (void)timeMethod{
? ? [NSThread sleepForTimeInterval:2.0];
? ? NSLog(@"timeMethod來(lái)了");
}
這個(gè)時(shí)候是不是拓動(dòng)UI的時(shí)候有卡頓現(xiàn)象利花。那么這種我們?nèi)绾翁幚聿挥绊慤I卡頓呢?
--此時(shí)此刻载佳,我們要記住每條線程都有一個(gè)RunLoop,默認(rèn)情況是不開(kāi)啟的炒事。
是不是現(xiàn)在又靈感有來(lái)了,我們把這個(gè)Timer丟到一個(gè)線程里面去
NSThread *thread =? [[NSThread alloc] initWithBlock:^{
??????????? NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(timeMethod) userInfo:nil repeats:YES];
??????????? [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
?????????? [[NSRunLoop currentRunLoop] run];//重點(diǎn)蔫慧,RunLoop,默認(rèn)情況是不開(kāi)啟的挠乳。注意要啟動(dòng)
?????????? NSLog(@"come here!");//這里不會(huì)打印,Runloop是死循環(huán)
??? }];
???
??? [thread start];
?
- (void)timeMethod{
??? [NSThread sleepForTimeInterval:2.0];
??? NSLog(@"timeMethod來(lái)了%@",[NSThread currentThread]);
}
運(yùn)行上面代碼姑躲,這個(gè)時(shí)候是不是不會(huì)出現(xiàn)UI卡頓了睡扬。
問(wèn)題有來(lái)l,RunLoop是不是停不下來(lái)了,要停下來(lái)黍析,要怎么玩卖怜?請(qǐng)看下面
NSThread *thread =? [[NSThread alloc] initWithBlock:^{
??????????? NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(timeMethod) userInfo:nil repeats:YES];
??????????? [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
?????? while (!_finished) {
?????????? [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.001]];
?????? }
????????? // [[NSRunLoop currentRunLoop] run];
?????????? NSLog(@"come here! %@",[NSThread currentThread]);
??? }];
???
??? [thread start];
?
}
- (void)timeMethod{
??? NSLog(@"timeMethod來(lái)了%@",[NSThread currentThread]);
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
??? _finished = YES;
}
一旦RunLoop停止,come here就好打印出來(lái)阐枣, 線程執(zhí)行完就釋放了马靠。
其實(shí)我們還有種簡(jiǎn)單方式處理這種需求
/GCD timer 設(shè)置Time
//注意要強(qiáng)引用self.timer
? self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(0, 0));
? ? dispatch_source_set_timer(self.timer, DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);//2 開(kāi)始時(shí)間 、持續(xù)時(shí)間蔼两、
? ? dispatch_source_set_event_handler(self.timer, ^{
? ? ? ? NSLog(@"GCD timer:%@", [NSThread currentThread]); //打印的是在子線程
? ? });
? ? dispatch_resume(self.timer); //啟動(dòng)