定時器NSTimer,CADisplayLink,dispatch_source_t

1、NSTimer特性

? ? ? ?timer實際觸發(fā)事件的時間與runloop有關(guān),如果此時的runloop在執(zhí)行一個耗時運算,timer就會被延時觸發(fā)。重復(fù)性的timer遇到這種情況,如果延遲超過一個周期,則會在延時結(jié)束后立即執(zhí)行,并按照之前指定的周期繼續(xù)執(zhí)行。

? ? ? ? 必須加入runloop,使用scheduledTimerWithTimeInterval創(chuàng)建的,會自動加入mainrunloop中NSDefaultRunloopMode中,如果使用其他方式創(chuàng)建,需要手動加入runloop

NSTimer*timer=[NSTimer timerWithTimeInterval:6 target:selfselector:@selector(timerAction)userInfo:nil repeats:YES];

[[NSRunLoop mainRunLoop]addTimer:timer forMode:NSDefaultRunLoopMode];

選擇的mode是default的話,當(dāng)滑動scrollView的時候,定時器是會停止的,你可以將mode設(shè)置為common


2.CADisplayLink特性

? ? ? ? CADisplayLink是一個以屏幕刷新率將特定的內(nèi)容畫到屏幕上的定時器。CADisplayLink以特定模式注冊到runloop后,每當(dāng)屏幕刷新顯示內(nèi)容結(jié)束,runloop就會向CADisplayLink指定的targret發(fā)送一次指定的selector消息,CADisplayLink類對應(yīng)的selector就會調(diào)用一次。

? ? ? ? 延遲iOS設(shè)備的屏幕刷新頻率是固定的,CADisplayLink在正常的情況下,會再每次刷新結(jié)束調(diào)用,精度高,但是在調(diào)試的方法比較耗時時,超過了屏幕的刷新周期,就會導(dǎo)致跳過若干次回調(diào)機會,如果CPU過于繁忙,無法保證屏幕的60次/秒的刷新率,就會導(dǎo)致跳過若干次回調(diào)的機會,跳過次數(shù)取決于CPU的忙碌程度。

使用場景:

? ? ? ? ?從原理上可以看出,CADisplayLink適合做界面不停重繪,比如視頻播放的時候,需要不斷的獲取下一幀用于界面渲染。


3.dispatch_source_t

與NSTimer和CADisplayLink相比,時間更準(zhǔn)確,可以使用子線程,解決時間在主線程卡UI問題。

NSTimer會受到主線程的任務(wù)影響,CADisplayLink會受到CPU的負(fù)載影響,產(chǎn)生延誤。

dispatch_source_t可以使用子線程,而且使用leeway參數(shù)指定可以接受的誤差來降低資源的消耗。

dispatch_source可以重復(fù)使用,在我們一個頁面上,需要多次用到時鐘的話,可以將dispatch_source_t保存為屬性,避免提前釋放,然后循環(huán)掛起和恢復(fù),就可以達(dá)到多次利用的效果。

dispatch_source_t的suspendhe和resume要依次進行,不然毀crash,而且必須現(xiàn)在resume的轉(zhuǎn)臺下才能執(zhí)行cancel,不然也會crash.

@property (nonatomic, strong) dispatch_source_t timer;@property (nonatomic, assign) BOOL isSuspend; //定時器掛起狀態(tài)isSuspend記錄下掛起的狀態(tài),因為dispatch_source_t的suspend和resume要依次進行,不然會crash,而且必須在resume的狀態(tài)下,才能執(zhí)行cancel,不然也會crash?。sSuspend默認(rèn)為YES,因為首次需要resume以啟動定時器!- (dispatch_source_t)timer{ if (!_timer) { _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)); uint64_t interval = (uint64_t)(XYHeyMediaPhotoTimerInterval * NSEC_PER_SEC); dispatch_source_set_timer(_timer, DISPATCH_TIME_NOW, interval, 0); @weakify(self); dispatch_source_set_event_handler(_timer, ^{ dispatch_async(dispatch_get_main_queue(), ^{ @strongify(self); [self updatePhotoProgress]; }); }); } return _timer;}創(chuàng)建定時器,設(shè)置線程,啟動時間,時間間隔,以及執(zhí)行block,如果只執(zhí)行一次,在block中調(diào)用cancel即可,我們這里默認(rèn)為repeat!- (void)resumeTimer{ if (self.isSuspend) { dispatch_resume(self.timer); self.isSuspend = NO; }}在需要啟動時鐘的時候調(diào)用上述方法resumeTimer,只有在已掛起的狀態(tài)才能執(zhí)行成功,同理,掛起操作:- (void)suspendTimer{ if (!self.isSuspend) { dispatch_suspend(self.timer); self.isSuspend = YES; }}利用resumeTimer和suspendTimer,就可以重復(fù)利用該定時器了??!當(dāng)我頁面銷毀的時候,要主動將定時器銷毀掉:




最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容