ios 使用GCD定时器

定时器我们首先想到是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);
}

项目中要是使用到就拿回去用用吧,我也是自己简单封装了一下,也有优化的余地根据需求修改吧~

你可能感兴趣的:(ios 使用GCD定时器)