×

iOS - GCD 实现定时器、倒计时

96
骑行怪状
2016.05.29 23:56* 字数 309

标签(空格分隔): 计时器 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 计时器,苹果已经有代码提示啦!
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);
}
日记本
Web note ad 1