實(shí)現(xiàn)方式
1.NSTimer
2.CADisplayLink
3.GCD定時(shí)器
一载弄、NSTimer
創(chuàng)建方式
NSTimer *timer1 = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(action) userInfo:NULL repeats:YES];
NSTimer *timer2 = [NSTimer timerWithTimeInterval:1 target:self selector:@selector(action) userInfo:NULL repeats:YES];
第一種已經(jīng)自動(dòng)將定時(shí)器加入了RunLoop中落君,模式默認(rèn)是NSDefaultRunLoopMode
第二種需要將創(chuàng)建的定時(shí)器需要手動(dòng)加入RunLoop中:[[NSRunLoop mainRunLoop] addTimer:timer2 forMode:NSDefaultRunLoopMode]
需要注意的是
1.UIScrollView 滑動(dòng)時(shí)執(zhí)行的是 UITrackingRunLoopMode,NSDefaultRunLoopMode被掛起,會(huì)導(dǎo)致定時(shí)器失效垃喊,等恢復(fù)為滑動(dòng)結(jié)束時(shí)才恢復(fù)定時(shí)器。
要想在scrollview滑動(dòng)的時(shí)候不影響計(jì)時(shí)
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes]
或者
[[NSRunLoop mainRunLoop] addTimer:timer forMode: UITrackingRunLoopMode]
[[NSRunLoop mainRunLoop] addTimer:timer forMode: NSDefaultRunLoopMode]
2.注意相互應(yīng)用的問題
//timer是self的屬性袜炕,self持有timer 而timer有通過target:self持有了self形成了死鎖本谜,所以通過下面的釋放是不行的。
-(void)dealloc{
[_timer invalidate];
_timer = nil;
}
應(yīng)該(這是靈活的偎窘,也可以在點(diǎn)擊返回按鈕的時(shí)候銷毀掉timer)
-(void)viewWillDisappear:(BOOL)animated{
[_timer invalidate];
_timer = nil;
}
特點(diǎn)
NSTimer 需要加入某個(gè)RunLoop中乌助,所以NSTimer的準(zhǔn)確性跟加入的RunLoop和RunLoopMode有關(guān)溜在,如果此RunLoop正在執(zhí)行一個(gè)連續(xù)性的運(yùn)算,timer就會(huì)被延時(shí)出發(fā)他托。
二掖肋、CADisplayLink
CADisplayLink對(duì)象是一個(gè)和屏幕刷新率同步的定時(shí)器對(duì)象。屏幕每刷新一次就執(zhí)行一次回調(diào)方法赏参,適合做界面渲染志笼。
正常情況iOS設(shè)備的屏幕刷新頻率是固定60Hz,如果CPU過于繁忙,無法保證屏幕60次/秒的刷新率把篓,就會(huì)導(dǎo)致跳過若干次調(diào)用回調(diào)方法的機(jī)會(huì)纫溃,跳過次數(shù)取決CPU的忙碌程度。
//創(chuàng)建
self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(action)];
//間隔的刷新次數(shù)
self.displayLink.frameInterval = 60;
//添加RunLoopMode這里和NSTimer一樣
[self.displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
//釋放
[self.displayLink invalidate];
self.displayLink = nil;
二韧掩、GCD定時(shí)器
GCD精度非常高
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
dispatch_source_set_timer(timer, dispatch_walltime(NULL, 0), 1*NSEC_PER_SEC, 0);//每秒執(zhí)行 第二個(gè)參數(shù)紊浩,當(dāng)我們使用 dispatch_time 或者 DISPATCH_TIME_NOW 時(shí),系統(tǒng)會(huì)使用默認(rèn)時(shí)鐘來進(jìn)行計(jì)時(shí)揍很。然而當(dāng)系統(tǒng)休眠的時(shí)候郎楼,默認(rèn)時(shí)鐘是不走的,也就會(huì)導(dǎo)致計(jì)時(shí)器停止窒悔。使用 dispatch_walltime 可以讓計(jì)時(shí)器按照真實(shí)時(shí)間間隔進(jìn)行計(jì)時(shí).
//第三個(gè)參數(shù)表示間隔時(shí)間呜袁。
dispatch_source_set_event_handler(timer, ^{
NSLog(@"bb===bb");
dispatch_async(dispatch_get_main_queue(), ^{
//這里返回主線程去跟新界面
});
if (2==3) {
// 一定要有dispatch_suspend(_timer)或dispatch_source_cancel(_timer)這兩句話來指定出口, 否則定時(shí)器不執(zhí)行 若是要無限循環(huán) 就像我這樣寫讓其永遠(yuǎn)執(zhí)行不到简珠。
dispatch_source_cancel(timer); //關(guān)閉定時(shí)器
}
});
//開啟定時(shí)器
dispatch_resume(timer);
GCD計(jì)時(shí)器開啟后立刻執(zhí)行阶界,而NSTimer是經(jīng)過一個(gè)間隔時(shí)間后才執(zhí)行第一次。