CADisplayLink NSTimer准时么,有什么更好的解决方案。

1.NSTimer 是依赖runLoop,runloop每跑一圈的任务不是一样的,每次花费的时间也不一致的,当最后一圈比较耗时时候,造成不准时

2.不准时使用方案:使用GCD定时器,GCD定时器直接跟系统内核挂钩不依赖于runloop

    //创建队列

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

   //创建timer  dispatch_source_t

    self.estimateTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);

   //设置时间

    dispatch_source_set_timer(self.estimateTimer, DISPATCH_TIME_NOW, 120 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);

   //设置回调

    dispatch_source_set_event_handler(self.estimateTimer, ^{

        dispatch_async(dispatch_get_main_queue(), ^{

        });

    });

    //开始定时器

    dispatch_resume(self.estimateTimer);

   // 关闭定时器

    dispatch_source_cancel(self.estimateTimer);

3.  建议使用定时器的场景选用GCD定时器

 

4. 封装一个GCD定时器

@interface SSTimer : NSObject

 + (NSString *)execTask:(void(^)(void))task

           start:(NSTimeInterval)start

        interval:(NSTimeInterval)interval

         repeats:(BOOL)repeats

           async:(BOOL)async;

+ (NSString *)execTask:(id)target

              selector:(SEL)selector

                 start:(NSTimeInterval)start

              interval:(NSTimeInterval)interval

               repeats:(BOOL)repeats

                 async:(BOOL)async; 

+ (void)cancelTask:(NSString *)name;

@end

 

@implementation SSTimer

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);

    });

}

 

+ (NSString *)execTask:(void (^)(void))task start:(NSTimeInterval)start interval:(NSTimeInterval)interval repeats:(BOOL)repeats async:(BOOL)async

{

    if (!task || start < 0 || (interval <= 0 && repeats)) return nil;

    // 队列

    dispatch_queue_t queue = async ? dispatch_get_global_queue(0, 0) : 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 *name = [NSString stringWithFormat:@"%zd", timers_.count];

    // 存放到字典中

    timers_[name] = timer;

    dispatch_semaphore_signal(semaphore_);

    

    // 设置回调

    dispatch_source_set_event_handler(timer, ^{

        task();

        

        if (!repeats) { // 不重复的任务

            [self cancelTask:name];

        }

    });

    

    // 启动定时器

    dispatch_resume(timer);

    

    return name;

}

 

+ (NSString *)execTask:(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 *)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_);

}

 

@end

posted @ 2021-05-27 11:16  syh-918  阅读(111)  评论(0)    收藏  举报