iOS中GCD定時(shí)器詳解
前言:CADisplayLink、NSTimer 不準(zhǔn)時(shí)
?CADisplayLink、NSTimer是基于RunLoop機(jī)制的,如果RunLoop的任務(wù)過于繁重,有可能會(huì)導(dǎo)致前兩個(gè)定時(shí)器不準(zhǔn)時(shí)。
舉個(gè)例子:
?加入我們創(chuàng)建了一個(gè)NSTimer定時(shí)器,每1秒鐘做任務(wù)。那么,什么時(shí)候執(zhí)行NSTimer呢?
?是在RunLoop跑圈的過程中執(zhí)行NSTimer定時(shí)器,而RunLoop跑完一圈執(zhí)行的時(shí)間不固定,也就導(dǎo)致有可能1秒鐘過去了,但是RunLoop還沒有執(zhí)行到定時(shí)器的任務(wù),那么,這就造成定時(shí)器有可能不準(zhǔn)時(shí)。
一、GCD 定時(shí)器
?GCD是不依賴與RunLoop,是直接跟系統(tǒng)內(nèi)核交互的。時(shí)間比較準(zhǔn)確。
GCD 定時(shí)器簡單的使用:
- (void)viewDidLoad { [super viewDidLoad]; NSLog(@"begin"); // 隊(duì)列 dispatch_queue_t queue = dispatch_get_main_queue(); // 創(chuàng)建定時(shí)器 dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue); // 設(shè)置時(shí)間 uint64_t start = 2.0; uint64_t interval = 1.0; dispatch_source_set_timer(timer, dispatch_time(DISPATCH_TIME_NOW, start * NSEC_PER_SEC), interval * NSEC_PER_SEC, 0); // 設(shè)置回調(diào) dispatch_source_set_event_handler(timer, ^{ NSLog(@"111"); }); // 啟動(dòng)定時(shí)器 dispatch_resume(timer); self.timer = timer; }
2022-07-05 17:42:46.674345+0800 Interview02-GCD定時(shí)器[13943:350556] begin
2022-07-05 17:42:48.675440+0800 Interview02-GCD定時(shí)器[13943:350556] 111
2022-07-05 17:42:49.675542+0800 Interview02-GCD定時(shí)器[13943:350556] 111
2022-07-05 17:42:50.675350+0800 Interview02-GCD定時(shí)器[13943:350556] 111
2022-07-05 17:42:51.674523+0800 Interview02-GCD定時(shí)器[13943:350556] 111
二、GCD 定時(shí)器的實(shí)現(xiàn)方案
第一步:封裝
#import <Foundation/Foundation.h> NS_ASSUME_NONNULL_BEGIN @interface RHGCDTimer : NSObject + (NSString *)timerWithBlockTask:(void(^)(void))blockTask star:(float)star interval:(float)interval repeat:(BOOL)repeat async:(BOOL)async; + (void)cancelTask:(NSString *)name; @end NS_ASSUME_NONNULL_END
#import "RHGCDTimer.h" static NSMutableDictionary *timersDict; static dispatch_semaphore_t semaphore; @implementation RHGCDTimer + (void)initialize { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ timersDict = [NSMutableDictionary dictionary]; semaphore = dispatch_semaphore_create(1);//創(chuàng)建一個(gè)信號(hào)量,只允許一個(gè)線程操作 }); } + (NSString *)timerWithBlockTask:(void (^)(void))blockTask star:(float)star interval:(float)interval repeat:(BOOL)repeat async:(BOOL)async { if (!blockTask || star<0 || (repeat && interval <= 0)) return nil; //創(chuàng)建隊(duì)列,隊(duì)列決定到時(shí)候任務(wù)是在哪個(gè)線程執(zhí)行 dispatch_queue_t queue = async ? dispatch_queue_create("myQueue", DISPATCH_QUEUE_SERIAL) : dispatch_get_main_queue(); //創(chuàng)建一個(gè)定時(shí)器 dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue); /** dispatch_source_set_timer 上面的定時(shí)器 dispatch_time_t start 開始時(shí)間 (typedef uint64_t dispatch_time_t;) uint64_t interval 間隔 uint64_t leeway 誤差一般寫0 */ dispatch_source_set_timer(timer, dispatch_time(DISPATCH_TIME_NOW, star * NSEC_PER_SEC), interval *NSEC_PER_SEC, 0); dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);//信號(hào)量 //定時(shí)器唯一標(biāo)識(shí) static int i = 0; NSString *name = [NSString stringWithFormat:@"%d", i++]; //放進(jìn)字典,就會(huì)產(chǎn)生強(qiáng)引用 timersDict[name] = timer; dispatch_semaphore_signal(semaphore); //設(shè)置回調(diào) dispatch_source_set_event_handler(timer, ^{ blockTask(); if (!repeat) {//如果非重復(fù)執(zhí)行 [self cancelTask:name];//取消定時(shí)器 } }); //啟動(dòng)定時(shí)器 dispatch_resume(timer); //GCD不需要銷毀 return name; } + (void)cancelTask:(NSString *)name { if (name.length == 0) return; dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); dispatch_source_t timer = timersDict[name]; if (!timer) return; dispatch_source_cancel(timer); [timersDict removeObjectForKey:name]; dispatch_semaphore_signal(semaphore); } @end
第二步:使用
#import "ViewController.h" #import "RHGCDTimer.h" @interface ViewController () @property (copy, nonatomic) NSString *task; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; self.task = [RHGCDTimer timerWithBlockTask:^{ NSLog(@"執(zhí)行任務(wù)---%@", [NSThread currentThread]); } star:2.0 interval:1.0 repeat:YES async:YES]; } - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { [RHGCDTimer cancelTask:self.task]; } @end
第三步:測試驗(yàn)證
2022-07-05 17:31:41.375918+0800 Interview02-GCD定時(shí)器[13519:337316] 執(zhí)行任務(wù)---<_NSMainThread: 0x600002448880>{number = 1, name = main}
2022-07-05 17:31:42.375935+0800 Interview02-GCD定時(shí)器[13519:337316] 執(zhí)行任務(wù)---<_NSMainThread: 0x600002448880>{number = 1, name = main}
2022-07-05 17:31:43.375871+0800 Interview02-GCD定時(shí)器[13519:337316] 執(zhí)行任務(wù)---<_NSMainThread: 0x600002448880>{number = 1, name = main}
到此這篇關(guān)于iOS中GCD定時(shí)器詳解的文章就介紹到這了,更多相關(guān)iOS GCD定時(shí)器內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
iOS版微信朋友圈識(shí)別圖片位置信息 如何實(shí)現(xiàn)?
這篇文章主要為大家詳細(xì)介紹了iOS版微信朋友圈識(shí)別圖片位置信息的實(shí)現(xiàn)方法2016-10-10詳解ios監(jiān)聽reloadData刷新列表完畢的時(shí)機(jī)
這篇文章主要介紹了詳解ios監(jiān)聽reloadData刷新列表完畢的時(shí)機(jī),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-11-11iOS中的UISearchBar搜索框組件基礎(chǔ)使用指南
iOS開發(fā)套件中自帶的UISearchBar搜索框我們平時(shí)經(jīng)??梢杂玫?我們可以在默認(rèn)的基礎(chǔ)上修改文字顏色、背景顏色和背景圖片等,這里我們稍微總結(jié)一下iOS中的UISearchBar搜索框組件基礎(chǔ)使用指南.2016-05-05IOS中UIImageView方法實(shí)現(xiàn)簡單動(dòng)畫
這篇文章主要介紹了IOS中UIImageView方法實(shí)現(xiàn)簡單動(dòng)畫的相關(guān)資料,需要的朋友可以參考下2017-05-05iOS開發(fā)中UIImageView控件的常用操作整理
這篇文章主要介紹了iOS開發(fā)中UIImageView控件的常用操作整理,代碼基于傳統(tǒng)的Objective-C,需要的朋友可以參考下2016-01-01UIMenuController在Cell內(nèi)部無法顯示的解決辦法(iOS9.2)
這篇文章主要為大家詳細(xì)介紹了UIMenuController在Cell內(nèi)部無法顯示的解決辦法,感興趣的小伙伴們可以參考一下2016-08-08