定时器我们首先想到是NSTimer,不过NSTimer 有的时候会不准确,那么怎么处理呢?
因为NSTimer 是在Runloop 中,runloop 也是一个跑圈,一圈回来的时间不确定所以导致NSTimer 不准确;而GCD 是系统内核中的,滑动也不收到影响。面试也容易被问到这个。
下面来看看代码:
static NSMutableDictionary *timers; //!< 存储任务
dispatch_semaphore_t semaphore;
+ (void)initialize
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
timers = [NSMutableDictionary dictionary];
semaphore = dispatch_semaphore_create(1);
});
}
// 返回一个 字符串 标记为任务id 方便定时器随时停止
+ (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);
// 字典操作的时候加一个锁处理
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) {
// 不重复的任务
[self cancelTak:name];
}
});
dispatch_resume(timer);
return name;
}
/// 取消定时任务
+ (void)cancelTak:(NSString *)name {
if (name.length == 0) return;
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
// 字典删除的时候不能操作字典所以也加个锁处理 保证安全
dispatch_source_t timer = timers[name];
if (timer) {
dispatch_source_cancel(timer);
[timers removeObjectForKey:name];
}
dispatch_semaphore_signal(semaphore);
}
项目中要是使用到就拿回去用用吧,我也是自己简单封装了一下,也有优化的余地根据需求修改吧~
网友评论