4.4 GCD->4.0 GCD 的定时器事件

作者: 蓝田_Loto | 来源:发表于2016-04-18 14:22 被阅读276次

    本文并非最终版本,如果想要关注更新或更正的内容请关注文集,联系方式详见文末,如有疏忽和遗漏,欢迎指正。


    本文相关目录:
    ==================== 所属文集:4.0 多线程 ====================
    4.1 多线程基础->1.0 进程 & 线程
    ······················ 2.0 多线程简介
    4.2 pthread
    4.3 NSThread->1.0 创建线程
    ····················· 2.0 线程属性
    ····················· 3.0 线程状态/线程生命周期
    ····················· 4.0 多线程安全隐患
    ····················· 5.0 线程间通讯和常用方法
    4.4 GCD->1.0 GCD简介和使用
    ·············· 2.0 线程间的通信
    ·············· 3.0 其他用法
    ·············· 4.0 GCD 的定时器事件
    4.5 NSOperation->1.0 NSOperation简介
    ························ 2.0 NSOperationQueue
    ························ 3.0 线程间通信
    ························ 4.0 自定义NSOperation
    4.6 RunLoop - 运行循环
    ===================== 所属文集:4.0 多线程 =====================


    实际上 RunLoop 底层也会用到 GCD 的东西,比如 RunLoop 是用 dispatch_source_t实现的 Timer。但同时 GCD 提供的某些接口也用到了 RunLoop, 例如 dispatch_async()。

    当调用dispatch_async(dispatch_get_main_queue(), block)时,libDispatch 会向主线程的 RunLoop 发送消息,RunLoop会被唤醒,并从消息中取得这个 block,并在回调 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__()
    里执行这个 block。但这个逻辑仅限于 dispatch 到主线程,dispatch 到其他线程仍然是由 libDispatch 处理的。


    【区别】NSTimer & GCD 的定时器:
    • CFRunLoopTimerRef 基本上说的就是 NSTimer,它受 RunLoop 的 Mode 影响
    • GCD 的定时器不受 RunLoop 的 Mode 影响

    代码示例:当滚动文字的时候,是不会影响 GCD的定时器的

    #import "ViewController.h"
    
    @interface ViewController ()
    // 定时器 (这里不用带*,因为dispatch_source_t就是个类,内部已经包含了*)
    @property(nonatomic, strong) dispatch_source_t timer;
    @end
    
    @implementation ViewController
    
    int count = 0;
    
    - (void)viewDidLoad {
      [super viewDidLoad];
    
      // 1、获得队列
      //    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
      dispatch_queue_t queue = dispatch_get_main_queue();
    
      // 2、创建一个定时器 (dispatch_source_t本质还是个OC对象)
      self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
    
      // 3、设置定时器的各种属性(几时开始任务,每隔多长时间执行一次)
    
      // 触发时间(何时开始执行第一个任务)
      // 比当前时间晚1秒
      dispatch_time_t start =
          dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC));
      // 马上就执行
      //  dispatch_time_t start1 = DISPATCH_TIME_NOW;
    
      // 时间间隔。GCD的时间参数,一般是纳秒(1秒 == 10的9次方纳秒)
      uint64_t interval = (uint64_t)(1.0 * NSEC_PER_SEC);
    
      // 设置定时器的各种属性:比当前时间晚1秒开始,每隔1s 执行一次
      // 参数:(1)定时器名字 (2)触发时间 (3)时间间隔 (4)0
      dispatch_source_set_timer(self.timer, start, interval, 0);
    
      // 4、设置定时器的内部回调
      dispatch_source_set_event_handler(self.timer, ^{
    
        NSLog(@"1------------%@", [NSThread currentThread]);
    
        count++;
    
        if (count == 4) {
          NSLog(@"1------------count=%d", count);
          // 取消定时器
          dispatch_cancel(self.timer);
          self.timer = nil;
        }
    
      });
    
      // 5、启动定时器
      dispatch_resume(self.timer);
      NSLog(@"启动1------------");
    }
    
    - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    
      // 1、获得队列
      //    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
      dispatch_queue_t queue = dispatch_get_main_queue();
    
      // 2、创建一个定时器 (dispatch_source_t本质还是个OC对象)
      self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
    
      // 3、设置定时器的各种属性(几时开始任务,每隔多长时间执行一次)
    
      // 触发时间(何时开始执行第一个任务)
      // 比当前时间晚1秒
      dispatch_time_t start =
          dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC));
      // 马上就执行
      //  dispatch_time_t start1 = DISPATCH_TIME_NOW;
    
      // 时间间隔。GCD的时间参数,一般是纳秒(1秒 == 10的9次方纳秒)
      uint64_t interval = (uint64_t)(1.0 * NSEC_PER_SEC);
    
      // 设置定时器的各种属性:比当前时间晚1秒开始,每隔1s 执行一次
      // 参数:(1)定时器名字 (2)触发时间 (3)时间间隔 (4)0
      dispatch_source_set_timer(self.timer, start, interval, 0);
    
      // 4、设置定时器的内部回调
      dispatch_source_set_event_handler(self.timer, ^{
    
        NSLog(@"2------------%@", [NSThread currentThread]);
    
        count++;
    
        if (count == 6) {
          NSLog(@"2------------count=%d", count);
          // 取消定时器
          dispatch_cancel(self.timer);
          self.timer = nil;
        }
    
      });
    
      // 5、启动定时器
      dispatch_resume(self.timer);
      NSLog(@"启动2------------");
    }
    
    - (void)didReceiveMemoryWarning {
      [super didReceiveMemoryWarning];
      // Dispose of any resources that can be recreated.
    }
    
    @end
    

    打印结果:

    GCD 定时器[1838:94718] 启动1------------
    GCD 定时器[1838:94718] 1------------<NSThread: 0x7fb853600430>{number = 1, name = main}
    GCD 定时器[1838:94718] 1------------<NSThread: 0x7fb853600430>{number = 1, name = main}
    GCD 定时器[1838:94718] 1------------<NSThread: 0x7fb853600430>{number = 1, name = main}
    GCD 定时器[1838:94718] 1------------<NSThread: 0x7fb853600430>{number = 1, name = main}
    GCD 定时器[1838:94718] 1------------count=4
    GCD 定时器[1838:94718] 启动2------------
    GCD 定时器[1838:94718] 2------------<NSThread: 0x7fb853600430>{number = 1, name = main}
    GCD 定时器[1838:94718] 2------------<NSThread: 0x7fb853600430>{number = 1, name = main}
    GCD 定时器[1838:94718] 2------------count=6
    

    本文源码 Demo 详见 Github
    https://github.com/shorfng/iOS_4.0_multithreading.git




    作者:蓝田(Loto)
    出处: 简书

    如果你觉得本篇文章对你有所帮助,请点击文章末尾下方“喜欢”
    如有疑问,请通过以下方式交流:
    评论区回复微信(加好友请注明“简书+称呼”)发送邮件shorfng@126.com



    本文版权归作者和本网站共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。

    相关文章

      网友评论

      • __西门吹雪:这个定时器如何关闭了?关闭了能不能再开启了?
        蓝田_Loto:@__西门吹雪 取消定时器dispatch_cancel,启动定时器dispatch_resume. 当点击屏幕的时候,执行到定时器回调方法时候,会先执行resume启动定时器(步骤5),然后继续执行定时器回调的方法的内部代码(步骤4),当内部代码(这里用的是循环)执行完毕,cancel取消定时器。

        demo已修改

        从demo 里可以看出,在某一个方法中关闭定时器是不能再次开启的,但是在其他方法中如果想要开启就需要重新创建

      本文标题:4.4 GCD->4.0 GCD 的定时器事件

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