美文网首页
GCD定时器的封装

GCD定时器的封装

作者: 分流替躺欧阳克 | 来源:发表于2019-06-12 11:26 被阅读0次

    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 <Foundation/Foundation.h>
    
    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定时器的封装

          本文链接:https://www.haomeiwen.com/subject/anacfctx.html