服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - IOS - iOS简单易用的GCD计时器的实现原理

iOS简单易用的GCD计时器的实现原理

2021-05-17 16:46幸福的小木子 IOS

在日常开发中总会碰到需要计时器的功能,常见的定时器有NSTimer、GCD、CADisplayLink。网上也有很多的教程介绍三者的区别,今天主要讲的是GCD这种方式使用以及封装。感兴趣的小伙伴们可以参考一下

前言

好久没更新文章了,在掘金第一次发文章,还是给自己立一个flag每周至少更新一篇文章,可能文章的质量还不是很如意,希望通过写文章来提高自己文笔,以及记录自己学习中的遇到的问题解决方案。

在学习ios过程中,想定大家对于定时器都不陌生,在日常开发中总会碰到需要计时器的功能,常见的定时器有nstimer、gcd、cadisplaylink。网上也有很多的教程介绍三者的区别,今天主要讲的是gcd这种方式使用以及封装。

三者概括区别

 

  优点 缺点
nstimer 使用简单 受runloop影响会导致计时不精准
cadisplaylink 精度高      cpu负载的时候会影响触发事件,且触发事件大于触发间隔会导致掉帧现象。
gcd 较精准 代码较多,基本不受其他影响

 

总结:nstimer和cadisplaylink易受影响,而gcd虽然代码多,但是可控性非常强。

gcd

?
1
2
3
4
5
6
7
8
9
10
/** 获取一个全局的线程来运行计时器*/
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);
/** 设置计时器, 这里是每10毫秒执行一次*/
dispatch_source_set_timer(timer, dispatch_walltime(nil, 0), 10*nsec_per_msec, 0);
/** 设置计时器的里操作事件*/
dispatch_source_set_event_handler(timer, ^{
 //do you want....
});

开启、继续已暂停的定时器

?
1
dispatch_resume(timer);

暂停定时器

?
1
2
3
4
5
/** 挂起的时候注意,多次暂停的操作会导致线程锁的现象,即多少次暂停,
*  对应多少次的继续操作,即dispatch_suspend和dispatch_resume
*  是成对出现的,计时器才会继续工作。
*/
dispatch_suspend(timer);

结束定时器

?
1
dispatch_source_cancel(timer);

构思封装

写代码之前构思好功能模块以及会遇到的问题的解决方案、代码逻辑,再来下手写代码,会有事半功倍的效果。

  • 必然包含开始、暂停、继续、停止、重置功能
  • 时间计算过程中因浮点数计算会丢失精度,计算过程应采用nsdecimal
  • 时间转换考虑到精度以及便利性,采用系统的时间转换方法,时区置为gmt
  • 由于app进入后台,若未开启后台任务的开关,计时器将会停止,再次进入app又会继续,故采用监听app状态的方式记录app进入后台与前台的时间戳,并与截止时间相比,是否继续计时还是结束计时并回调。
  • 计时器返回的结果若采用字符串则还需处理,故使用了一个时间类来把结果返回,可以进行自定义操作
  • 倒计时的结果返回和结束通知采用闭包形式

部分代码

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
/** app进入后台*/
- (void)appdidenterbackground{
  [self suspend];
  nsdate *date = [[nsdate alloc] init];
  nsdateformatter *format = [[nsdateformatter alloc] init];
  format.dateformat = @"yyyy-mm-dd hh:mm:ss:sss";
  self.appdidenterbackgroundtime = [date timeintervalsince1970];
}
 
/** app进入前台*/
- (void)appdidenterforeground{
  nsdate *date = [[nsdate alloc] init];
  nsdateformatter *format = [[nsdateformatter alloc] init];
  format.dateformat = @"yyyy-mm-dd hh:mm:ss";
  self.appdidenterforegroundtime = [date timeintervalsince1970];
  [self recalculateminder];
}
 
/** 不失精度加减乘除计算结果*/
 
- (nsdecimalnumber *)value: (nstimeinterval)value
        byopration: (omdecimaloprationtype)byopration   
         percision: (nsinteger)percision
        withvalue: (nstimeinterval)withvalue{
 
  nsdecimalnumber *number = [self numbervaluewithstring: value];
  nsdecimalnumber *withnumber = [self numbervaluewithstring: withvalue];
  nsdecimalnumberhandler *handler = [nsdecimalnumberhandler decimalnumberhandlerwithroundingmode: nsroundplain scale: percision raiseonexactness: no raiseonoverflow: no raiseonunderflow: no raiseondividebyzero: yes];
 
switch (byopration) {
  case omdecimaloprationtypeadd:
   return [number decimalnumberbyadding: withnumber withbehavior:handler];
   break;
  case omdecimaloprationtypesubtract:
   return [number decimalnumberbysubtracting: withnumber withbehavior: handler];
   break;
  case omdecimaloprationtypedivide:
   return [number decimalnumberbydividingby: withnumber withbehavior: handler];
   break;
 case omdecimaloprationtypemultiple:
   return [number decimalnumberbymultiplyingby: withnumber withbehavior: handler];
   break;
 default:
   break;
   return nil;
}
?
1
@property (nonatomic, strong) omtimer *timer;
?
1
2
3
4
5
6
7
8
9
self.timer = [[omtimer alloc] init];
self.timer.timerinterval = 30;
self.timer.precision = 100;
self.timer.isascend = no;
self.timer.progressblock = ^(omtime *progress) {
   nslog(@"%@:%@:%@:%@", progress.hour, progress.minute, progress.second, progress.millisecond;
};self.timer.completion = ^{
  nslog(@"complete done!");
};

swift版本

最近喜欢上了oc,如有小伙伴需要swift的版本的话可以留言或者私我,可以在写个swift版本,:stuck_out_tongue_winking_eye:。

结语

使用简单,只需要把omtimer.h和omtimer.m拖入你的工程即可,满足大数的场景,可倒计时亦可增加计时,全部代码已在github<https://github.com/oymuzi/omkit/

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。

原文链接:https://juejin.im/post/5bf934e56fb9a049b2218b0b

延伸 · 阅读

精彩推荐
  • IOSiOS中tableview 两级cell的展开与收回的示例代码

    iOS中tableview 两级cell的展开与收回的示例代码

    本篇文章主要介绍了iOS中tableview 两级cell的展开与收回的示例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...

    J_Kang3862021-04-22
  • IOSiOS 雷达效果实例详解

    iOS 雷达效果实例详解

    这篇文章主要介绍了iOS 雷达效果实例详解的相关资料,需要的朋友可以参考下...

    SimpleWorld11022021-01-28
  • IOS解析iOS开发中的FirstResponder第一响应对象

    解析iOS开发中的FirstResponder第一响应对象

    这篇文章主要介绍了解析iOS开发中的FirstResponder第一响应对象,包括View的FirstResponder的释放问题,需要的朋友可以参考下...

    一片枫叶4662020-12-25
  • IOSiOS通过逆向理解Block的内存模型

    iOS通过逆向理解Block的内存模型

    自从对 iOS 的逆向初窥门径后,我也经常通过它来分析一些比较大的应用,参考一下这些应用中某些功能的实现。这个探索的过程乐趣多多,不仅能满足自...

    Swiftyper12832021-03-03
  • IOSiOS布局渲染之UIView方法的调用时机详解

    iOS布局渲染之UIView方法的调用时机详解

    在你刚开始开发 iOS 应用时,最难避免或者是调试的就是和布局相关的问题,下面这篇文章主要给大家介绍了关于iOS布局渲染之UIView方法调用时机的相关资料...

    windtersharp7642021-05-04
  • IOSIOS开发之字典转字符串的实例详解

    IOS开发之字典转字符串的实例详解

    这篇文章主要介绍了IOS开发之字典转字符串的实例详解的相关资料,希望通过本文能帮助到大家,让大家掌握这样的方法,需要的朋友可以参考下...

    苦练内功5832021-04-01
  • IOSIOS 屏幕适配方案实现缩放window的示例代码

    IOS 屏幕适配方案实现缩放window的示例代码

    这篇文章主要介绍了IOS 屏幕适配方案实现缩放window的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要...

    xiari5772021-06-01
  • IOS关于iOS自适应cell行高的那些事儿

    关于iOS自适应cell行高的那些事儿

    这篇文章主要给大家介绍了关于iOS自适应cell行高的那些事儿,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的...

    daisy6092021-05-17