标签(空格分隔): 计时器 GCD timer 倒计时
GCD 定时器
NSTimer 的定时器是在 RunLoop 中实现的,由于RunLoop在处理各种任务,所以会造成计时器不够准确,有时候会相对慢一些,有没有什么方法会让计时变得准确?有,使用 GCD 的计时器方法会让计时器变得相对准确,而且GCD不受RunLoop的 Mode 影响。
GCD 延时
我们之前写过延时执行的方法,其中 GCD 有一个延时执行的方法,,只执行一次,执行完后,就不再执行.如下代码在这里等待两秒钟后执行,执行之后就结束了,不能起到定时器的作用.
//延时执行
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"-------延时执行--------");
});
GCD 定时器的实现
在之前写一个GCD的定时器很麻烦,需要一步步创建,现在XCode中已经有Timer的创建提示,选择箭头所指的方法,直接能过创建。
如下:
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, <#dispatchQueue#>);
dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, <#intervalInSeconds#> * NSEC_PER_SEC, <#leewayInSeconds#> * NSEC_PER_SEC);
dispatch_source_set_event_handler(timer, ^{
<#code to be executed when timer fires#>
});
dispatch_resume(timer);
我们需要做的是,选择其队列类型,这里我选择的是全局队列。
创建 计时器 (参数注解)
/**
* GCD 计时器应用
* dispatch Queue :决定了将来回调的方法在哪里执行。
* dispatch_source_t timer 是一个OC对象
* DISPATCH_TIME_NOW 第二个参数:定时器开始时间,也可以使用如下的方法,在Now 的时间基础上再延时多长时间执行以下任务。
dispatch_time(<#dispatch_time_t when#>, <#int64_t delta#>)
* intervalInSeconds 第三个参数:定时器开始后的间隔时间(纳秒 NSEC_PER_SEC)
* leewayInSeconds 第四个参数:间隔精准度,0代标最精准,传入一个大于0的数,代表多少秒的范围是可以接收的,主要为了提高程序性能,积攒一定的时间,Runloop执行完任务会睡觉,这个方法让他多睡一会,积攒时间,任务也就相应多了一点,而后一起执行
*/
// 全局队列
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
// 创建一个 timer 类型定时器 ( DISPATCH_SOURCE_TYPE_TIMER)
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
//设置定时器的各种属性(何时开始,间隔多久执行)
// GCD 的时间参数一般为纳秒 (1 秒 = 10 的 9 次方 纳秒)
// 指定定时器开始的时间和间隔的时间
dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC, 0);
// 任务回调
dispatch_source_set_event_handler(timer, ^{
NSLog(@"-----定时器-------");
});
// 开始定时器任务(定时器默认开始是暂停的,需要复位开启)
dispatch_resume(timer);
GCD实现验证码倒计时
// 开启倒计时效果
- (IBAction)openCountdown:(id)sender {
__block NSInteger time = 59; //倒计时时间
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
dispatch_source_set_timer(timer,DISPATCH_TIME_NOW,1.0*NSEC_PER_SEC, 0); //每秒执行
dispatch_source_set_event_handler(timer, ^{
if(time <= 0){ //倒计时结束,关闭
dispatch_source_cancel(timer);
dispatch_async(dispatch_get_main_queue(), ^{
//设置按钮的样式
[self.openSeconds setTitle:@"重新发送" forState:UIControlStateNormal];
self.timeLabel.text = @"开始";
self.openSeconds.userInteractionEnabled = YES;
});
}else{
int seconds = time % 60;
dispatch_async(dispatch_get_main_queue(), ^{
//设置label读秒效果
self.timeLabel.text = [NSString stringWithFormat:@"重新发送(%.2d)",seconds];
[self.openSeconds setTitle:@"已发送" forState:UIControlStateNormal];
// 在这个状态下 用户交互关闭,防止再次点击 button 再次计时
self.openSeconds.userInteractionEnabled = NO;
});
time--;
}
});
dispatch_resume(timer);
}