GCD timer

推荐使用GCD方式创建timer的原因,GCD是基于内核的,会更加准时,NSTimer和CADisplayLink依赖于RunLoop,如果Runloop的任务太繁重,可能会导致NSTimer不准时

GCD的Timer创建

//stong修饰,强引用
@property (nonatomic,strong) dispatch_source_t timer;

  • (void)viewDidLoad {
    [super viewDidLoad];
    NSLog(@"begin");
    // Do any additional setup after loading the view.
    // 队列
    // dispatch_queue_t queue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_SERIAL);
    // dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    dispatch_queue_t queue = 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_NOW, 1 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
    // 设置时间,带有延时几秒后执行的开启定时器的参数
    dispatch_source_set_timer(timer, dispatch_time(DISPATCH_TIME_NOW, 2NSEC_PER_SEC), 1NSEC_PER_SEC, 0);
    // 设置回调
    dispatch_source_set_event_handler(timer, ^{
    // 上面设置为什么队列,这个回调就在什么队列里面执行
    NSLog(@"执行定时器");
    NSLog(@"%@",[NSThread currentThread]);
    });
    // 启动定时器
    dispatch_resume(timer);
    // 设置timer为强引用的,否则不会执行,出了函数调用栈,就销毁了
    self.timer = timer;
    }
    封装一个timer对象

.h

@interface JGTimer : NSObject
//开始定时器的方法
+(NSString *)execTask:(void(^)(void))task start:(NSTimeInterval)start interval:(NSTimeInterval)interval repeats:(BOOL)repeats async:(BOOL)async;
//取消定时器
+(void)cancleTask:(NSString *)name;
@end
.m

import "JGTimer.h"

@implementation JGTimer

//使用字典来表示,任务的名字和timer一一对应的关系,设置一个全局的字典
static NSMutableDictionary * timers_;
//使用信号量来解决多线程,同时操作字典的情况
dispatch_semaphore_t semaphore_ ;

// 使用initialize和单例初始化字典,因为只有给这个类发送消息时候来回调用这个方法
+(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;
}
__weak typeof(self) weakSelf = self;

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:@"%lu",(unsigned long)timers_.count];
// 给定时器增加强引用,并且是任务的名字和定时器一一对应
timers_[name] = timer;
dispatch_semaphore_signal(semaphore_);
// 设置回调
dispatch_source_set_event_handler(timer, ^{
task();
// 如果取消这个任务,执行一次就取消
if (!repeats) {
[weakSelf cancleTask:name];
}
});
// 启动
dispatch_resume(timer);
return name;
}
+(void)cancleTask:(NSString *)name{
if (name.length == 0) {
return;
}
dispatch_source_t timer = timers_[name];
if (!timer) return;
// 如果信号的值为1的话,会自动减1,然后执行下面的代码,如果这个值为0,就会休眠等待,直到这个值大于0时候,才会唤醒和继续执行
dispatch_semaphore_wait(semaphore_, DISPATCH_TIME_FOREVER);
// 取消定时器
dispatch_source_cancel(timers_[name]);
// 从字典中删除这个定时器,删除强引用
[timers_ removeObjectForKey:name];
// 信号的值+1操作
dispatch_semaphore_signal(semaphore_);
}
使用封装的定时器

  • (void)viewDidLoad {
    [super viewDidLoad];
    /*
    NSLog(@"begin");
    // 队列
    // dispatch_queue_t queue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_SERIAL);
    // dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    dispatch_queue_t queue = 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_NOW, 1 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
    // 设置时间,带有延时几秒后执行的开启定时器的参数
    dispatch_source_set_timer(timer, dispatch_time(DISPATCH_TIME_NOW, 2NSEC_PER_SEC), 1NSEC_PER_SEC, 0);
    // 设置回调
    dispatch_source_set_event_handler(timer, ^{
    // 上面设置为什么队列,这个回调就在什么队列里面执行
    NSLog(@"执行定时器");
    NSLog(@"%@",[NSThread currentThread]);
    });
    // 启动定时器
    dispatch_resume(timer);
    // 设置timer为强引用的,否则不会执行,出了函数调用栈,就销毁了
    self.timer = timer;

    */

// 封装timer
NSLog(@"begin");
self.task = [JGTimer execTask:^{
NSLog(@"111");
} start:2 interval:1 repeats:YES async:YES];
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
// 取消定时器
[JGTimer cancleTask:self.task];
}

你可能感兴趣的:(GCD timer)