定時(shí)器我們首先想到是NSTimer,不過(guò)NSTimer 有的時(shí)候會(huì)不準(zhǔn)確肴裙,那么怎么處理呢?
因?yàn)镹STimer 是在Runloop 中涌乳,runloop 也是一個(gè)跑圈蜻懦,一圈回來(lái)的時(shí)間不確定所以導(dǎo)致NSTimer 不準(zhǔn)確夕晓;而GCD 是系統(tǒng)內(nèi)核中的征炼,滑動(dòng)也不收到影響。面試也容易被問到這個(gè)。
下面來(lái)看看代碼:
static NSMutableDictionary *timers; //!< 存儲(chǔ)任務(wù)
dispatch_semaphore_t semaphore;
+ (void)initialize
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
timers = [NSMutableDictionary dictionary];
semaphore = dispatch_semaphore_create(1);
});
}
// 返回一個(gè) 字符串 標(biāo)記為任務(wù)id 方便定時(shí)器隨時(shí)停止
+ (NSString *)execStart:(NSTimeInterval)start
interval:(NSTimeInterval)interval
repeats:(BOOL)repeats
isMainThread:(BOOL)async
task:(void (^)(void))task {
if (!task || start < 0 || (interval <=0 && repeats)) return nil;
dispatch_queue_t queue = async ? dispatch_get_main_queue() : dispatch_get_global_queue(0, 0);
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
// 字典操作的時(shí)候加一個(gè)鎖處理
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
NSString *name = [NSString stringWithFormat:@"%zd",timers.count];
timers[name] = timer;
dispatch_semaphore_signal(semaphore);
dispatch_source_set_timer(timer,
dispatch_time(DISPATCH_TIME_NOW, start * NSEC_PER_SEC),
interval * NSEC_PER_SEC, 0);
dispatch_source_set_event_handler(timer, ^{
task();
if (!repeats) {
// 不重復(fù)的任務(wù)
[self cancelTak:name];
}
});
dispatch_resume(timer);
return name;
}
/// 取消定時(shí)任務(wù)
+ (void)cancelTak:(NSString *)name {
if (name.length == 0) return;
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
// 字典刪除的時(shí)候不能操作字典所以也加個(gè)鎖處理 保證安全
dispatch_source_t timer = timers[name];
if (timer) {
dispatch_source_cancel(timer);
[timers removeObjectForKey:name];
}
dispatch_semaphore_signal(semaphore);
}
項(xiàng)目中要是使用到就拿回去用用吧,我也是自己簡(jiǎn)單封裝了一下填帽,也有優(yōu)化的余地根據(jù)需求修改吧~