GCD定时器的封装

NSTimer依赖于Runloop,如果Runloop的任务过于繁重,可能会导致NSTimer不准时。
而GCD定时器依赖于操作系统内核,更加准时。
GCD定时器的一些API:

//创建一个定时器
//type:DISPATCH_SOURCE_TYPE_TIMER//代表创建的是定时器
//handle:监视系统的句柄
//mask:需要哪些事件的掩码
//queue:放在哪个队列
dispatch_source_t timer = dispatch_source_create(dispatch_source_type_t type,
    uintptr_t handle,
    unsigned long mask,
    dispatch_queue_t _Nullable queue);
//设置时间
//source:传入GCD创建的timer,
//start:开始时间,GCD对象的timer,使用dispatch_time(DISPATCH_TIME_NOW, start*NSEC_PER_SEC)创建,DISPATCH_TIME_NOW从现在开始 start*NSEC_PER_SEC纳秒后(GCD里以纳秒为单位)
//interval*NSEC_PER_SEC:interval*NSEC_PER_SEC个纳秒执行一次
//leeway:允许的误差。
dispatch_source_set_timer(dispatch_source_t source,
    dispatch_time_t start,
    uint64_t interval,
    uint64_t leeway);
//设置回调的两个方法,一个是block,一个传入函数名
dispatch_source_set_event_handler(dispatch_source_t source,
    dispatch_block_t _Nullable handler);
dispatch_source_set_event_handler_f(timer, timerFunc);
//启动
dispatch_resume(timer);

封装一个定时器,继承于NSObject的好处是可以防止别人调用别的其父类的别的接口
h文件:

#import 

NS_ASSUME_NONNULL_BEGIN

@interface CS_Timer : NSObject
+ (NSString*)execTask:(void(^)(void))task start:(NSTimeInterval)start interval:(NSTimeInterval)interval repeats:(BOOL)repeats async:(BOOL)async;

+ (NSString*)execTarget:(id)target selector:(SEL)selector start:(NSTimeInterval)start interval:(NSTimeInterval)interval repeats:(BOOL)repeats async:(BOOL)async;

+ (void)cancelTask:(NSString*)TimerName;
@end

NS_ASSUME_NONNULL_END

m文件

#import "CS_Timer.h"

@implementation CS_Timer
static NSMutableDictionary *timers;
dispatch_semaphore_t semaphore;
+ (void)initialize{
    static dispatch_once_t onceToken;
    semaphore = dispatch_semaphore_create(1);
    dispatch_once(&onceToken, ^{
        timers = [[NSMutableDictionary alloc]init];
    });
    
}

+ (NSString*)execTask:(void(^)(void))task start:(NSTimeInterval)start interval:(NSTimeInterval)interval repeats:(BOOL)repeats async:(BOOL)async
{
    if (!task || (interval<0 && repeats)|| start<= 0) return nil;
    
    
    dispatch_queue_t queue = async?queue = dispatch_queue_create("asyncQueue", DISPATCH_QUEUE_SERIAL):dispatch_get_main_queue();
    
    dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
    
    dispatch_source_set_timer(timer, dispatch_time(DISPATCH_TIME_NOW, start*NSEC_PER_SEC), interval*NSEC_PER_SEC, 0);//最后一个参数,允许的纳秒误差。
    
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    NSString *timerName = [NSString stringWithFormat:@"timerNo_%ld",timers.count];
    timers[timerName] = timer;
    dispatch_semaphore_signal(semaphore);
    
    dispatch_source_set_event_handler(timer, ^{
        task();
        if(!repeats)
          [self cancelTask:timerName];
    });
    dispatch_resume(timer);
    return timerName;
}

+ (NSString*)execTarget:(id)target selector:(SEL)selector start:(NSTimeInterval)start interval:(NSTimeInterval)interval repeats:(BOOL)repeats async:(BOOL)async
{
    if (!target || !selector) return nil;
    return [self execTask:^{
        if ([target respondsToSelector:selector]) {
//消除警告
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
            [target performSelector:selector];
#pragma clang diagnostic pop

        }
    } start:start interval:interval repeats:repeats async:async];
}

+ (void)cancelTask:(NSString *)timerName{
    if (timerName.length == 0) return;
    
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);

    dispatch_source_t timer = timers[timerName];
    
    if (timer) {
        dispatch_source_cancel(timers[timerName]);
        [timers removeObjectForKey:timerName];
    }
    
    dispatch_semaphore_signal(semaphore);
}

void timerFunc()
{
    NSLog(@"GCD 回调方法");
}
@end

你可能感兴趣的:(GCD定时器的封装)